rendered paste bodyusing 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("<", "<");
token.Replace(">", ">");
}*/
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) {}
}
}