All pastes #790873 Raw Edit

TextParser

public text v1 · immutable
·published 2007-11-20 17:20 UTC
rendered paste body
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Text;

namespace BloggerLibrary
{
    public class TextParser
    {
        private const char HtmlOpenChar = '<';
        private const char HtmlCloseChar = '>';
        private const char HtmlEndToken = '/';

        private const char CustomOpenChar = '[';
        private const char CustomCloseChar = ']';
        private const char CustomEndToken = '/';

        private const char quoteChar = '"';


        //Holds the tags that the parser will accept
        private Dictionary<string, string> tagMap = new Dictionary<string, string>();

        //Holds the tags found in the text, when the closing tags are found the items are pushed off the stack.
        //Which in well formed forum html will produce an empty stack when parsing has finished
        private Stack<string> tagStack = new Stack<string>();

        //When anything ordinary replacing needs to be done outside a tag.
        private Dictionary<string, string> replaceMap = new Dictionary<string, string>();

        //When anything from regularexpressions needs to be replaced outside a tag
        private Dictionary<string, string> regExpReplaceMap = new Dictionary<string, string>();

        //Critical map contains critical replaces, that should be done even when inside a noparse tag!
        private Dictionary<string, bool> criticalMap = new Dictionary<string, bool>();

        //Critical map contains critical replaces for regular expressions
        private Dictionary<string, bool> criticalRegExpMap = new Dictionary<string,bool>();

        //Defines tags which contents will not be parsed (ex. quote tags)
        private Dictionary<string, bool> noTouchMap = new Dictionary<string, bool>();

        //Holds values for parameters
        private Dictionary<string, string> parameterMap = new Dictionary<string, string>();

        private bool stripHTMLTags = true;

        public bool StripHTMLTags
        {
            get { return stripHTMLTags; }
            set { stripHTMLTags = value; }
        }
	

        public void AddTag(string tag, string htmlTag)
        {
            AddTag(tag, htmlTag, String.Empty);
        }
        public void AddTag(string tag, string htmlTag, string parameter)
        {
            AddTag(tag, htmlTag, parameter, false);
        }
        public void AddTag(string tag, string htmlTag, string parameter, bool noTouch)
        {
            if (tagMap.ContainsKey(tag))
            {
                throw new TextParserException("The tag has already been added to the tag map");
            }
            tagMap.Add(tag, htmlTag);
            if (noTouch)
            {
                noTouchMap.Add(tag, true);
            }
            if (!String.IsNullOrEmpty(parameter))
            {
                parameterMap.Add(tag, parameter);
            }
        }
        public void AddReplace(string match, string replace)
        {
            AddReplace(match, replace, false, false);
        }

        public void AddReplace(string match, string replace, bool regularExpression)
        {
            AddReplace(match, replace, regularExpression, false);
        }
        public void AddReplace(string match, string replace, bool regularExpression, bool critical)
        {
            if (!regularExpression)
            {
                if (replaceMap.ContainsKey(match))
                {
                    throw new TextParserException("The match string has already been added to the replace map");
                }
                replaceMap.Add(match, replace);
                if (critical)
                {
                    criticalMap.Add(match, true);
                }
            }
            else
            {
                if (replaceMap.ContainsKey(match))
                {
                    throw new TextParserException("The match string has already been added to the replace map");
                }
                regExpReplaceMap.Add(match, replace);
                if (critical)
                {
                    criticalRegExpMap.Add(match, true);
                }
            }
        }
        private string text;

        public TextParser(string text){
            this.text = text;
        }
        public TextParser()
        {
        }

        public string TextToParse {
            get {
                return text;
            }
            set {
                text = value;
            }
        }

        private string GetUserParameter(string tagName, string userArg){
            if (parameterMap.ContainsKey(tagName))
            {
                string param = parameterMap[tagName];
                if (param.Contains("$"))
                {
                    return " " + param.Replace("$", userArg);
                }
                else
                {
                    return " " + param;
                }
            }
            else
            {
                return String.Empty;
            }
        }
        public string Parse()
        {
            StringBuilder sb = new StringBuilder();

            bool inTag = false;
            bool inBeginTag = false;
            bool inEndTag = false;
            bool noParse = false;
            bool inUserParam = false;
            bool inQuote = false;

            int textSize = text.Length;

            string currentTag = String.Empty;
            string userParam = String.Empty;

            StringBuilder currentToken = new StringBuilder();
            foreach (char c in text)
            {
                if(inTag)
                {
                    if (c == CustomCloseChar)
                    {
                        currentToken.Append(CustomOpenChar);
                        currentToken.Append(CustomCloseChar);
                    }
                    else if (c == CustomEndToken)
                    {
                        inTag = false;
                        inEndTag = true;
                    }
                    else if(!noParse)
                    {
                        currentTag += c;
                        inTag = false;
                        inBeginTag = true;
                    } else {
                        inTag = false;
                        currentToken.Append(CustomOpenChar);
                        currentToken.Append(c);
                    }
                }
                else if (inBeginTag)
                {
                    if (c == CustomCloseChar && !inQuote)
                    {
                        inBeginTag = false;
                        if (tagMap.ContainsKey(currentTag))
                        {
                            string tag = tagMap[currentTag];
                            tagStack.Push(currentTag);
                            PerformReplace(noParse, ref currentToken);
                            sb.Append(currentToken);
                            currentToken = new StringBuilder();
                            sb.Append(HtmlOpenChar);
                            sb.Append(tag);
                            sb.Append(GetUserParameter(currentTag, userParam));
                            sb.Append(HtmlCloseChar);
                            if (noTouchMap.ContainsKey(currentTag))
                            {
                                noParse = true;
                            }
                        }
                        else
                        {
                            currentToken.Append(CustomOpenChar);
                            currentToken.Append(currentTag);
                            if(userParam != String.Empty)
                                currentToken.Append('=' + userParam);
                            currentToken.Append(CustomCloseChar);
                        }
                        userParam = String.Empty;
                        currentTag = String.Empty;
                        inUserParam = false;
                    }
                    else if(c == CustomCloseChar && inQuote)
                    {
                        currentToken.Append(CustomOpenChar);
                        currentToken.Append(currentTag);
                        currentToken.Append('=');
                        currentToken.Append(quoteChar);
                        currentToken.Append(userParam);
                        currentToken.Append(CustomCloseChar);
                        inBeginTag = false;
                        inQuote = false;
                        inUserParam = false;
                        currentTag = String.Empty;
                    }
                    else if (c == quoteChar)
                    {
                        if(!inQuote){
                            if(inUserParam){
                                inQuote = true;
                            } else {
                                currentToken.Append(CustomOpenChar);
                                currentToken.Append(currentTag);
                                currentToken.Append(quoteChar);
                                inBeginTag = false;
                                currentTag = String.Empty;
                            }
                        } else {
                            inQuote = false;
                        }
                    }
                    else if (c == '=')
                    {
                        if (!inUserParam)
                        {
                            inUserParam = true;
                        }
                        else
                        {
                            if (inQuote)
                            {
                                userParam += c;
                            }
                            else
                            {
                                currentToken.Append(CustomOpenChar);
                                currentToken.Append(currentTag);
                                currentToken.Append('=');
                                if (inQuote)
                                    currentToken.Append('"');

                                currentToken.Append(userParam);
                                currentToken.Append('=');
                                inBeginTag = false;
                                inQuote = false;
                                inUserParam = false;
                                currentTag = String.Empty;
                                userParam = String.Empty;
                            }
                        }
                    }
                    else
                    {
                        if (inUserParam)
                        {
                            userParam += c;
                        }
                        else
                        {
                            currentTag += c;
                        }
                    }
                }
                else if (inEndTag)
                {
                    if (c != CustomCloseChar)
                    {
                        currentTag += c;
                    }
                    else
                    {
                        inEndTag = false;
                        if (!noParse || noTouchMap.ContainsKey(currentTag))
                        {
                            if (tagMap.ContainsKey(currentTag))
                            {
                                string tag = tagMap[currentTag];
                                bool outputHtmlEndTag = true;
                                if (!EnsureTagStack(currentTag, ref currentToken, sb, noParse)) //If this expression returns true then we need to manually output the opening tag
                                {
                                    outputHtmlEndTag = false;
                                }
                                //Output close tag
                                if (outputHtmlEndTag)
                                {
                                    //No need to output current token, EnsureTagStack does that, but reset the current token
                                    currentToken = new StringBuilder();

                                    sb.Append(HtmlOpenChar);
                                    sb.Append(HtmlEndToken);
                                    sb.Append(tag);
                                    sb.Append(HtmlCloseChar);
                                }
                                else
                                {
                                    currentToken.Append(CustomOpenChar);
                                    currentToken.Append(CustomEndToken);
                                    currentToken.Append(currentTag);
                                    currentToken.Append(CustomCloseChar);
                                }
                                if (noTouchMap.ContainsKey(currentTag))
                                {
                                    noParse = false;
                                }

                            }
                            else
                            {
                                currentToken.Append(CustomOpenChar);
                                currentToken.Append(CustomEndToken);
                                currentToken.Append(currentTag);
                                currentToken.Append(CustomCloseChar);
                            }
                        }
                        else
                        {
                           
                            currentToken.Append(CustomOpenChar);
                            currentToken.Append(CustomEndToken);
                            currentToken.Append(currentTag);
                            currentToken.Append(CustomCloseChar);
                        }
                        currentTag = String.Empty;
                    }           

                }
                else
                {
                    if (c == CustomOpenChar)
                    {
                        inTag = true;
                    }
                    else
                    {
                        currentToken.Append(c);
                    }
                }
            }
            PerformReplace(noParse, ref currentToken);
            sb.Append(currentToken);
            while (tagStack.Count > 0)
            {
                string tag = tagMap[tagStack.Pop()];
                sb.Append(HtmlOpenChar + HtmlEndToken + tag + HtmlCloseChar);

            }
            return sb.ToString();
        }

        private void PerformReplace(bool noParse, ref StringBuilder currentToken)
        {

            if (!noParse)
            {
                foreach (KeyValuePair<string, string> entry in replaceMap)
                {
                    currentToken.Replace(entry.Key, entry.Value);
                }
                foreach (KeyValuePair<string, string> entry in regExpReplaceMap)
                {
                    Regex reg = new Regex(entry.Key);
                    currentToken = new StringBuilder(reg.Replace(currentToken.ToString(), entry.Value));
                }
            }
            foreach (KeyValuePair<string, bool> entry in criticalMap)
            {
                if (entry.Value)
                {
                    string replace = replaceMap[entry.Key];
                    currentToken.Replace(entry.Key, replace);
                }
            }
            foreach (KeyValuePair<string, bool> entry in criticalRegExpMap)
            {
                if (entry.Value)
                {
                    string replace = regExpReplaceMap[entry.Key];
                    Regex reg = new Regex(entry.Key);
                    currentToken = new StringBuilder(reg.Replace(currentToken.ToString(), replace));
                }
            }
        }
        private bool EnsureTagStack(string tag, ref StringBuilder token, StringBuilder output, bool noParse)
        {
            if (!tagStack.Contains(tag))
            {
                return false;
            }
            /*if (StripHTMLTags)
            {
                token.Replace("<", "&lt;");
                token.Replace(">", "&gt;");
            }*/
            PerformReplace(noParse, ref token);

            output.Append(token.ToString());
            string tagStackTag = tagStack.Pop();
            while (tagStackTag != tag)
            {
                string htmlTag = tagMap[tagStackTag];
                output.Append(HtmlOpenChar.ToString() + HtmlEndToken.ToString() + htmlTag + HtmlCloseChar);
                tagStackTag = tagStack.Pop();
            }
            return true;
        }
    }
    public class TextParserException : Exception
    {
        public TextParserException(string message) : base(message) {}
    }
}