using System; using System.Data; using System.Configuration; using System.Text; using System.Collections.Generic; using System.Collections; namespace BloggerLibrary { public interface ITextParserTag { public string ProduceOutput(string content, string parameter); } public class TextParserTag : ITextParserTag { private string output; public string Output { get { return output.Replace(":questionmarkgoeshere:", "?").Replace(":moniesformepls:", "$"); } set { output = value.Replace("?", ":questionmarkgoeshere:").Replace("$", ":moniesformepls:"); } } protected string RealOutput { get { return output; } set { output = value; } } public virtual TextParserTag(string output) { this.Output = output; } private string ReplaceReservedChars(string str){ return str.Replace("?", ":questionmarkgoeshere:").Replace("$", ":moniesformepls:"); } private string ReplaceReservedCharsBack(string str){ return str.Replace(":questionmarkgoeshere:", "?").Replace(":moniesformepls:", "$"); } public string ProduceOutput(string content, string parameter){ string value = ReplaceReservedCharsBack(Output.Replace("?", parameter).Replace("$", content)); return value; } } public class ImprovedTextParser { class Tag { public StringBuilder Parameter; public StringBuilder Content; internal Tag() { Parameter = new StringBuilder(); Content = new StringBuilder(); } } private bool boolStripHTMLTags = true; public bool StripHTMLTags { get { return boolStripHTMLTags; } set { boolStripHTMLTags = value; } } private const char customOpenTag = '['; private const char customCloseTag = ']'; private const char customEndToken = '/'; private const char HTMLOpenTag = '<'; private const char HTMLCloseTag = '>'; private const char HTMLEndToken = '/'; private Dictionary tagMap = new Dictionary(); Stack> tagStack = new Stack>(); private string textToParse; public string TextToParse { get { return textToParse; } set { textToParse = value; } } public ImprovedTextParser(string textToParse) { TextToParse = textToParse; } public ImprovedTextParser() : this(String.Empty) { } public void AddTag(string customTag, TextParserTag tagInfo) { tagMap.Add(customTag, tagInfo); } public string Parse() { string text = (StripHTMLTags) ? stripHTMLTags(TextToParse) : TextToParse; bool searchForNextTag = true; bool inTag = false, inCloseTag = false; string currentTag = String.Empty; StringBuilder sb = new StringBuilder(); StringBuilder appendTo = sb; int i = 0, n = text.Length; while (i < n) { char curChar = text[i]; if (searchForNextTag) { int g = i; i = text.IndexOf(customOpenTag, g); if (i < 0) { i = n; } if (i != g) { string textToAppend = DoStuffWithToken(text.Substring(g, i - g)); appendTo.Append(textToAppend); } if (i == n) { break; //we're done } searchForNextTag = false; curChar = text[i]; //Make sure this one is pointing to the right character } if (curChar == customOpenTag) { inTag = true; } else if (inTag) { if (curChar == customEndToken) { inCloseTag = true; } else if (curChar == customCloseTag) { if (inCloseTag) { if (tagMap.ContainsKey(currentTag) && tagStack.Peek().Key == currentTag) { //We have a closing tag which exists in the tagMap and is the next tag that needs to be closed Tag tag = tagStack.Pop().Value; StringBuilder tagContent = tag.Content; //Get all the content that is within this tag StringBuilder tagParam = tag.Parameter; if (tagStack.Count > 0) //Need to see if we need to append this to anything new { //If there's any more tags we need to append it to that tag and not the outer most stringbuilder appendTo = tagStack.Peek().Value.Content; } else { appendTo = sb; } appendTo.Append(tagMap[currentTag].ProduceOutput(tagContent.ToString(), tagParam.ToString())); } else { //Tag non existent or would produce bad code, just output the code for it appendTo.Append(customOpenTag + customEndToken + currentTag + customCloseTag); } inTag = false; //Reset to default values inCloseTag = false; currentTag = String.Empty; } else { //Must be opening tag //Check if the tag is something we need to act on or not if (tagMap.ContainsKey(currentTag)) { //Lets rock KeyValuePair tagData = new KeyValuePair(currentTag, new Tag()); tagStack.Push(tagData); //simply add the tag to the tagStack appendTo = tagData.Value.Content; //Make sure all future stuff will go to this tag } else { //No match - lets just output the stuff and pretend we never saw it appendTo.Append(customOpenTag + currentTag + customCloseTag); } inTag = false; currentTag = String.Empty; } searchForNextTag = true; } else { //For now just assume it'll be a part of the tag - later on we need to parse parameters and etc currentTag += curChar; } } i++; } while(tagStack.Count > 0){ KeyValuePair tagData = tagStack.Pop(); TextParserTag parserTag = tagMap[tagData.Key]; sb.Append(parserTag.ProduceOutput(tagData.Value.Content.ToString(), tagData.Value.Content.ToString())); } return sb.ToString(); } private string DoStuffWithToken(string p) { return p; } private string stripHTMLTags(string txt) { return txt.Replace(HTMLOpenTag.ToString(), "<").Replace(HTMLCloseTag.ToString(), ">"); } } }