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<string, TextParserTag> tagMap = new Dictionary<string, TextParserTag>();
Stack<KeyValuePair<string, Tag>> tagStack = new Stack<KeyValuePair<string, Tag>>();
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<string, Tag> tagData = new KeyValuePair<string, Tag>(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<string, Tag> 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(), ">");
}
}
}