public static string HtmlToShopCode(string text, ShopModule module) { text = text.Trim(); // replace line breaks, get block elements right text = text.Replace("\r\n", ""); text = Regex.Replace(text, @"((?<!(\A|<blockquote>|</blockquote>|</p>))(<blockquote>|<p>))", "</p>$1", RegexOptions.IgnoreCase | RegexOptions.Compiled); text = Regex.Replace(text, @"(</blockquote>|</p>)((?!(<p>|<blockquote>|</blockquote>))(.*</p>))", "$1<p>$2", RegexOptions.IgnoreCase | RegexOptions.Compiled); text = Regex.Replace(text, "^<p>", "", RegexOptions.IgnoreCase); text = Regex.Replace(text, "</p>$", "", RegexOptions.IgnoreCase); text = Regex.Replace(text, "<blockquote>", "\r\n[quote]", RegexOptions.IgnoreCase); text = Regex.Replace(text, "</blockquote>", "[/quote]\r\n", RegexOptions.IgnoreCase); text = Regex.Replace(text, "<p>", "\r\n", RegexOptions.IgnoreCase); text = Regex.Replace(text, "</p>", "\r\n", RegexOptions.IgnoreCase); text = Regex.Replace(text, "<br>", "\r\n", RegexOptions.IgnoreCase); text = Regex.Replace(text, "<br/>", "\r\n", RegexOptions.IgnoreCase); text = Regex.Replace(text, "<br />", "\r\n", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"\[quote\](?!(\r\n))", "[quote]\r\n", RegexOptions.IgnoreCase | RegexOptions.Compiled); text = Regex.Replace(text, @"(?<!(\r\n))\[/quote\]", "\r\n[/quote]", RegexOptions.IgnoreCase | RegexOptions.Compiled); IList tEc = module.GetAllEmoticons(); if(tEc != null) { foreach (ShopEmoticon Item in tEc) { text = Regex.Replace(text, "<img src=\"" + module.ThemePath + Item.ImageName + "\">", Item.TextVersion, RegexOptions.IgnoreCase); text = Regex.Replace(text, "<img src=\"" + module.ThemePath + Item.ImageName + "\"/>", Item.TextVersion, RegexOptions.IgnoreCase); text = Regex.Replace(text, "<img src=\"" + module.ThemePath + Item.ImageName + "\" />", Item.TextVersion, RegexOptions.IgnoreCase); } } // replace basic tags IList tFtc = module.GetAllTags(); if(tFtc != null) { foreach (ShopTag Item in tFtc) { text = Regex.Replace(text, Item.HtmlCodeStart, Item.ShopCodeStart, RegexOptions.IgnoreCase); text = Regex.Replace(text, Item.HtmlCodeEnd, Item.ShopCodeEnd, RegexOptions.IgnoreCase); } } text = Regex.Replace(text, @"</a>", "[/url]", RegexOptions.IgnoreCase); // replace img and a tags text = Regex.Replace(text, @"(<a href="")(\S+)("" target=""_blank"">)", "[url=\"$2\"]", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"(<a href="")(\S+)("" target=_blank>)", "[url=\"$2\"]", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"(<a href="")(\S+)("">)", "[url=\"$2\"]", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"(<a href="")(\S+)("">)", "[url=\"$2\"]", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"(<img src="")(\S+)("">)", "[image=\"$2\"]", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"(<img src="")(\S+)("" />)", "[image=\"$2\"]", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"(<img src="")(\S+)(""/>)", "[image=\"$2\"]", RegexOptions.IgnoreCase); // catch remaining HTML as invalid text = Regex.Replace(text, @"<.*>", "", RegexOptions.IgnoreCase); // convert HTML escapes text = Regex.Replace(text, " ", " ", RegexOptions.IgnoreCase); text = Regex.Replace(text, "&", "&", RegexOptions.IgnoreCase); text = Regex.Replace(text, "<", "<", RegexOptions.IgnoreCase); text = Regex.Replace(text, ">", ">", RegexOptions.IgnoreCase); return text.Trim(); }
public static string ShopCodeToHtml(string text,ShopModule module) { text = text.Trim(); // build stack of shop codes, look for closure and proper nesting Regex openPattern = new Regex(@"\[(?!/)[\w""\?=&/;\+%\*\:~,\.\-\$@#]+\]", RegexOptions.IgnoreCase); Regex closePattern = new Regex(@"\[/\w+\]", RegexOptions.IgnoreCase); Regex bothPattern = new Regex(@"\[[\w""\?=&/;\+%\*\:~,\.\-\$@#]+\]", RegexOptions.IgnoreCase); ArrayList stack = new ArrayList(); Match allMatches = bothPattern.Match(text); int indexAfterLastClosingTag = 0; while (allMatches.Success) { string tag = allMatches.ToString(); if (openPattern.IsMatch(tag)) { // it's an opening tag, add it to the stack stack.Add(tag); allMatches = allMatches.NextMatch(); } else { // if it's a closing URL tag, disregard //if (tag == "[/url]") break; // this is a closing tag. see if it matches the previous opening tag if (stack.Count == 0) { // there are no more opening tags on the stack, so we'll have to insert one after the last closer string newCloser = tag.Replace("[/", "["); text = text.Insert(indexAfterLastClosingTag, newCloser); allMatches = bothPattern.Match(text, indexAfterLastClosingTag + newCloser.Length); } else { // opening tags left on the stack... string tempOpen = (string)stack[stack.Count - 1]; if (tempOpen.StartsWith("[url=")) tempOpen = "[url]"; if (tag.Replace("[/", "[") == tempOpen) { // it matches the last opening tag, remove it from the stack stack.RemoveAt(stack.Count - 1); indexAfterLastClosingTag = allMatches.Index + tag.Length; allMatches = allMatches.NextMatch(); } else { // closer doesn't match last opener string previousOpeningTag = (string)stack[stack.Count - 1]; stack.RemoveAt(stack.Count - 1); // put a closing tag before it string newCloser = previousOpeningTag.Replace("[", "[/"); text = text.Insert(allMatches.Index, newCloser); indexAfterLastClosingTag = allMatches.Index + newCloser.Length; // if there's a future closing tag of the same type, we need an opener after this closer MatchCollection futureClosers = closePattern.Matches(text, indexAfterLastClosingTag); foreach (Match futureClose in futureClosers) { if (futureClose.ToString() == previousOpeningTag.Replace("[", "[/")) { text = text.Insert(indexAfterLastClosingTag + tag.Length, previousOpeningTag); break; } } allMatches = bothPattern.Match(text, indexAfterLastClosingTag); } } } } // convert HTML escapes text = Regex.Replace(text, "&", "&", RegexOptions.IgnoreCase); text = Regex.Replace(text, "<", "<", RegexOptions.IgnoreCase); text = Regex.Replace(text, ">", ">", RegexOptions.IgnoreCase); // identify URL's that don't have url shop code so we can parse them to be links. Regex protolcPattern = new Regex(@"(?<theurl>(?<!(\]|""))(((news|(ht|f)tp(s?))\://)[\w\-\*]+(\.[\w\-/~\*]+)*/?)([\w\?=&/;\+%\*\:~,\.\-\$#])*)", RegexOptions.Compiled | RegexOptions.IgnoreCase); Regex wwwPattern = new Regex(@"(?<theurl>(?<!(\]|""|//))(?<=\s|^)(w{3}(\.[\w\-/~\*]+)*/?)([\?\w=&;\+%\*\:~,\-\$#])*)", RegexOptions.Compiled | RegexOptions.IgnoreCase); Regex emailPattern = new Regex(@"(?<theurl>(?<=\s|\])(?<!(mailto:|""\]))([\w\.\-_']+)@(([\w\-]+\.)+[\w\-]+))", RegexOptions.Compiled | RegexOptions.IgnoreCase); text = protolcPattern.Replace(text, "[url=\"${theurl}\"]${theurl}[/url]"); text = wwwPattern.Replace(text, "[url=\"http://${theurl}\"]${theurl}[/url]"); text = emailPattern.Replace(text, "[url=\"mailto:${theurl}\"]${theurl}[/url]"); // replace URL tags text = Regex.Replace(text, @"(\[url="")(\S+?)(""\])", "<a href=\"$2\" target=\"_blank\">", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"(<a href=\""mailto:)(\S+?)(\"" target=\""_blank\"">)", "<a href=\"mailto:$2\">", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"\[/url\]", "</a>", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"(\[image="")(\S+?)(""\])", "<img src=\"$2\" />", RegexOptions.IgnoreCase); // replace basic tags IList tFtc = module.GetAllTags(); if(tFtc != null) { foreach (ShopTag Item in tFtc) { text = Regex.Replace(text, Regex.Escape(Item.ShopCodeStart), Item.HtmlCodeStart, RegexOptions.IgnoreCase); text = Regex.Replace(text, Regex.Escape(Item.ShopCodeEnd), Item.HtmlCodeEnd, RegexOptions.IgnoreCase); } } IList tEc = module.GetAllEmoticons(); if(tEc != null) { foreach (ShopEmoticon Item in tEc) { text = Regex.Replace(text, Regex.Escape(Item.TextVersion), "<img src=\"" + module.ThemePath + Item.ImageName + "\" />", RegexOptions.IgnoreCase); } } // replace line breaks, get block elements right //if (!text.StartsWith("[quote]")) text = "<p class=shop>" + text; //if (!text.EndsWith("[/quote]")) text += "</p>"; text = Regex.Replace(text, @"\[quote\]", "<blockquote>", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"\[/quote\]", "</blockquote>", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"(?<!(</blockquote>))\r\n\r\n(?!(<p>|<blockquote>|</blockquote>))", "</p><p>", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"(?<=(</p>|<blockquote>|</blockquote>|\A))(\r\n)*<blockquote>", "<blockquote>", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"\r\n\r\n<blockquote>", "</p><blockquote>", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"<blockquote>\r\n(?!(<p>|<blockquote>|</blockquote>))", "<blockquote><p>", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"(?<!(</p>|<blockquote>|</blockquote>))\r\n</blockquote>", "</p></blockquote>", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"</blockquote>\r\n\r\n", "</blockquote><p>", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"</blockquote>\r\n</blockquote>", "</blockquote></blockquote>", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"(?<!(</p>|<blockquote>|</blockquote>|\A))<blockquote>", "</p><blockquote>", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"<blockquote>(?!(<p>|<blockquote>|</blockquote>))", "<blockquote><p>", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"(?<!(</p>|<blockquote>|</blockquote>))</blockquote>", "</p></blockquote>", RegexOptions.IgnoreCase); text = Regex.Replace(text, @"</blockquote>(\r\n)?(?!(<p>|<blockquote>|</blockquote>|\Z))", "</blockquote><p>", RegexOptions.IgnoreCase); text = text.Replace("\r\n", "<br />"); text = TextParser.Censor(text); return text.Trim(); }