/// <summary> /// �������������� ������. /// <b>������������������!</b> /// </summary> /// <param name="txt">�������� �����.</param> /// <param name="smile">������� ��������� ���������.</param> /// <param name="doNotReplaceTags">�� �������� ��������� ������� HTML.</param> /// <param name="doNotFormatImplicitLinks">�� ������������� ���� �� ��������� ������.</param> /// <returns>���������������� �����.</returns> public virtual string Format( string txt, bool smile, bool doNotReplaceTags, bool doNotFormatImplicitLinks) { var sb = new StringBuilder(txt); sb.Trim(TrimArray); if (sb.IsEmpty()) return ""; // ��������! ������� �������������� �����. // // ������ ������������ �������� if (!doNotReplaceTags) sb = sb.ReplaceTagsWQ(); // ���������� ���� ����� ������ ����� � \n // sb = _rxNewLineUnifier.Replace(sb, "\n"); // ��������� �������� ����� � �����, // ������� �� ����� ���� ������ ����������. // // temporary remove [code...] tags const string codeExpression = "$$code{0}$$"; var codeMatcher = new Matcher(codeExpression); sb = _rxCodeFormatting.Replace(sb, codeMatcher.Match); // temporary remove [img] tags const string imgExpression = "$$img{0}$$"; var imgMatcher = new Matcher(imgExpression); sb = _imgTagRegex.Replace(sb, imgMatcher.Match); // temporary remove [url] & [purl] tags const string urlExpression = "$$url{0}$$"; var urlMatcher = new Matcher(urlExpression); sb = _urlTagRegex.Replace(sb, urlMatcher.Match); // temporary remove implicit links const string implicitUrlExpression = "$$iurl{0}$$"; var implicitUrlMatcher = new Matcher(implicitUrlExpression); if (!doNotFormatImplicitLinks) sb = _urlRegex.Replace(sb, implicitUrlMatcher.Match); // temporary remove [q] tags const string quoteExpression = "$$quote{0}$$"; var quoteMatcher = new Matcher(quoteExpression); sb = _rxPrep12.Replace(sb, quoteMatcher.Match); // temporary remove [cut] tags const string cutExpression = "$$cut{0}$$"; Matcher cutMatcher; do { cutMatcher = new Matcher(cutExpression); sb = _rxPrep13.Replace(sb, cutMatcher.Match); // �����������. sb = _rxTextUrl09.Replace(sb, "<span class='lineQuote'>$&</span>"); // restore & transform [cut] tags for (var i = 0; i < cutMatcher.Count; i++) { var m = cutMatcher[i]; var capt = String.IsNullOrEmpty(m.Groups[3].Value) ? "������� �����" : m.Groups[3].Value; sb = sb.Replace(String.Format(cutExpression, i), _hiddenTextSnippet.Replace("%CAPT%", capt).Replace("%TEXT%", m.Groups[4].Value). Replace("%URL%", GetImagePrefix())); } } while (cutMatcher.Count > 0); // restore & transform [q] tags // ����������� [q]. // http://www.rsdn.ru/forum/?mid=111506 for (var i = 0; i < quoteMatcher.Count; i++) sb = sb.Replace( string.Format(quoteExpression, i), string.Format( "<blockquote class='q'><p>{0}</p></blockquote>", quoteMatcher[i].Groups[1])); // ��������� ��������� � ������ ������ � http://www.rsdn.ru/forum/?mid=184751 if (smile) { var prefix = GetImagePrefix(); sb = _smileReplacers.Aggregate( sb, (current, replacer) => replacer.Replace(current, prefix)); } // ISBN sb = _isbnDetector.Replace( sb, match => { var isbn = new StringBuilder(match.Length); foreach (Capture capture in match.Groups["isbn"].Captures) { isbn.Append(capture.Value).Append('-'); } if (isbn.Length > 0) isbn.Length--; return ProcessISBN(match, isbn.ToString()); }); // restore & transform [url] and [purl] tags for (var i = 0; i < urlMatcher.Count; i++) { var url = urlMatcher[i].Groups["url"].Value; var tag = urlMatcher[i].Groups["tag"].Value; // ���� url � tag ����������: // if (!Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute)) // ���� tag �� ������ // if (!String.IsNullOrEmpty(tag)) // ���� tag ���������� Uri // if (Uri.IsWellFormedUriString(tag, UriKind.RelativeOrAbsolute)) { // // var temp = tag; tag = url; url = temp; } sb = sb.Replace( string.Format(urlExpression, i), ProcessURLs(url, tag)); } // restore & transform implicit links for (var i = 0; i < implicitUrlMatcher.Count; i++) sb = sb.Replace( string.Format(implicitUrlExpression, i), ProcessImplicitURLs(implicitUrlMatcher[i])); // restore & transform [img] tags for (var i = 0; i < imgMatcher.Count; i++) sb = sb.Replace( string.Format(imgExpression, i), ImagesDelegate(this, imgMatcher[i])); // RSDN links sb = _rsdnLinkDetector.Replace(sb, ProcessRsdnLink); // [email] sb = _emailTagRegex.Replace(sb, ProcessEmailLink); // Replace hyphen to dash sb = _dashDetector.Replace(sb, "—"); // [tagline] sb = _taglineDetector.Replace(sb, "<div class='tagline'>$1</div>"); // [list] sb = _rxPrep06.Replace(sb, @"<ul style='margin-top:0; margin-bottom:0;'>$1</ul>"); // [list=..] sb = _rxPrep07.Replace(sb, ListEvaluator); // [*] sb = _rxPrep08.Replace(sb, "<li />"); // [hr] sb = _rxPrep09.Replace(sb, "<hr />"); // Q12345(6) sb = _rxPrep10.Replace( sb, @"<a target='_blank' class='m' href='http://support.microsoft.com/default.aspx?scid=kb;EN-US;$1'>$1</a>"); // ��������� ����������. sb = _moderatorDetector.Replace(sb, "<div class='mod'>$1</div>"); // Table sb = _rxTable.Replace( sb, "<table class='formatter' border='0' cellspacing='2' cellpadding='5'>$1</table>"); sb = _rxTableRow.Replace(sb, "<tr class='formatter'>$1</tr>"); sb = _rxTableHeader.Replace(sb, "<th class='formatter'>$1</th>"); sb = _rxTableColumn.Replace(sb, "<td class='formatter'>$1</td>"); // Headers sb = _rxHeaders.Replace(sb, "<h$2 class='formatter'>$1</h$2>"); // ��������� � ����� ������ ������ <br />, // �� �� ����� </table>, </div>, </ol>, </ul>, <blockquote> (�������� ������ <span>) // � �� � ����� ����� ������ sb = _rxNewLines.Replace(sb, "<br />$0"); sb = _inlineTagReplacers.Aggregate(sb, (cur, replacer) => replacer(cur)); // ������ �� MSDN. sb = _rxMsdn.Replace(sb, DoMSDNRef); // ����� ��� ������ ����� � ������ ���������. sb = _rxPrep01.Replace(sb, ""); sb = _rxPrep02.Replace(sb, ""); sb = _rxPrep03.Replace(sb, ""); // restore & transform [code] tags for (var i = 0; i < codeMatcher.Count; i++) { // code coloring var code = PaintCode(codeMatcher[i]); // bold & italic formatting inside code // without checking canceling tag syntax code = _inlineTagReplacersNoChecks.Aggregate(code, (cur, replacer) => replacer(cur)); sb = sb.Replace(string.Format(codeExpression, i), code.ToString()); } return sb.ToString(); }
/// <summary> /// Форматирование текста. /// <b>НЕПОТОКОБЕЗОПАСНЫЙ!</b> /// </summary> /// <param name="txt">Исходный текст.</param> /// <param name="smile">Признак обработки смайликов.</param> /// <param name="doNotReplaceTags">Не заменять служебные символы HTML.</param> /// <param name="doNotFormatImplicitLinks">Не форматировать явно не указанные ссылки.</param> /// <returns>Сформатированный текст.</returns> public virtual string Format( string txt, bool smile, bool doNotReplaceTags, bool doNotFormatImplicitLinks) { var sb = new StringBuilder(txt); sb.Trim(TrimArray); if (sb.IsEmpty()) return ""; // Внимание! Порядок преобразования ВАЖЕН. // // Замена небезопасных символов if (!doNotReplaceTags) sb = sb.ReplaceTagsWQ(); // Приведение всех типов концов строк к \n // sb = _rxNewLineUnifier.Replace(sb, "\n"); // Обработка исходных кодов и тегов, // которые не могут быть внутри исходников. // // temporary remove [code...] tags const string codeExpression = "$$code{0}$$"; var codeMatcher = new Matcher(codeExpression); sb = _rxCodeFormatting.Replace(sb, codeMatcher.Match); // temporary remove [img] tags const string imgExpression = "$$img{0}$$"; var imgMatcher = new Matcher(imgExpression); sb = _imgTagRegex.Replace(sb, imgMatcher.Match); // temporary remove [url] & [purl] tags const string urlExpression = "$$url{0}$$"; var urlMatcher = new Matcher(urlExpression); sb = _urlTagRegex.Replace(sb, urlMatcher.Match); // temporary remove implicit links const string implicitUrlExpression = "$$iurl{0}$$"; var implicitUrlMatcher = new Matcher(implicitUrlExpression); if (!doNotFormatImplicitLinks) sb = _urlRegex.Replace(sb, implicitUrlMatcher.Match); // temporary remove [q] tags const string quoteExpression = "$$quote{0}$$"; var quoteMatcher = new Matcher(quoteExpression); sb = _rxPrep12.Replace(sb, quoteMatcher.Match); // temporary remove [cut] tags const string cutExpression = "$$cut{0}$$"; Matcher cutMatcher; do { cutMatcher = new Matcher(cutExpression); sb = _rxPrep13.Replace(sb, cutMatcher.Match); // Цитирование. sb = _rxTextUrl09.Replace(sb, m => $"<span class='lineQuote level{WebUtility.HtmlDecode(m.Groups["lev"].Value).Length}'>{m.Groups[0].Value}</span>"); // restore & transform [cut] tags for (var i = 0; i < cutMatcher.Count; i++) { var m = cutMatcher[i]; var capt = String.IsNullOrEmpty(m.Groups[3].Value) ? "Скрытый текст" : m.Groups[3].Value; sb = sb.Replace(String.Format(cutExpression, i), _hiddenTextSnippet.Replace("%CAPT%", capt).Replace("%TEXT%", m.Groups[4].Value). Replace("%URL%", GetImagePrefix())); } } while (cutMatcher.Count > 0); // restore & transform [q] tags // Цитирование [q]. // http://www.rsdn.ru/forum/?mid=111506 for (var i = 0; i < quoteMatcher.Count; i++) sb = sb.Replace( string.Format(quoteExpression, i), $"<blockquote class='q'><p>{quoteMatcher[i].Groups[1]}</p></blockquote>"); // Обработка смайликов с учетом отмены и http://www.rsdn.ru/forum/?mid=184751 if (smile) { var prefix = GetImagePrefix(); sb = _smileReplacers.Aggregate( sb, (current, replacer) => replacer.Replace(current, prefix)); } // ISBN sb = _isbnDetector.Replace( sb, match => { var isbn = new StringBuilder(match.Length); foreach (Capture capture in match.Groups["isbn"].Captures) { isbn.Append(capture.Value).Append('-'); } if (isbn.Length > 0) isbn.Length--; return ProcessISBN(match, isbn.ToString()); }); // restore & transform [url] and [purl] tags for (var i = 0; i < urlMatcher.Count; i++) { var url = urlMatcher[i] .Groups["url"] .Value; var tag = urlMatcher[i].Groups["tag"].Value; // если url и tag перепутаны: // if (!Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute)) // если tag не пустой // if (!String.IsNullOrEmpty(tag)) // если tag правильный Uri // if (Uri.IsWellFormedUriString(tag, UriKind.RelativeOrAbsolute)) { // // var temp = tag; tag = url; url = temp; } url = url.Replace("&", "&"); // Returns escaped ampersands sb = sb.Replace( string.Format(urlExpression, i), ProcessURLs(url, tag)); } // restore & transform implicit links for (var i = 0; i < implicitUrlMatcher.Count; i++) sb = sb.Replace( string.Format(implicitUrlExpression, i), ProcessImplicitURLs(implicitUrlMatcher[i])); // restore & transform [img] tags for (var i = 0; i < imgMatcher.Count; i++) sb = sb.Replace( string.Format(imgExpression, i), ImagesDelegate(this, imgMatcher[i])); // RSDN links sb = _rsdnLinkDetector.Replace(sb, ProcessRsdnLink); // [email] sb = _emailTagRegex.Replace(sb, ProcessEmailLink); // Replace hyphen to dash sb = _dashDetector.Replace(sb, "—"); // [tagline] sb = _taglineDetector.Replace(sb, "<div class='tagline'>$1</div>"); // [list] sb = _rxPrep06.Replace(sb, @"<ul style='margin-top:0; margin-bottom:0;'>$1</ul>"); // [list=..] sb = _rxPrep07.Replace(sb, ListEvaluator); // [*] sb = _rxPrep08.Replace(sb, "<li />"); // [hr] sb = _rxPrep09.Replace(sb, "<hr />"); // Q12345(6) sb = _rxPrep10.Replace( sb, @"<a target='_blank' class='m' href='http://support.microsoft.com/default.aspx?scid=kb;EN-US;$1'>$1</a>"); // Сообщение модератора. sb = _moderatorDetector.Replace(sb, "<div class='mod'>$1</div>"); // Table sb = _rxTable.Replace( sb, "<table class='formatter' border='0' cellspacing='2' cellpadding='5'>$1</table>"); sb = _rxTableRow.Replace(sb, "<tr class='formatter'>$1</tr>"); sb = _rxTableHeader.Replace(sb, "<th class='formatter'>$1</th>"); sb = _rxTableColumn.Replace(sb, "<td class='formatter'>$1</td>"); // Headers sb = HeadersRegex.Replace(sb, "<h$2 class='formatter'>$1</h$2>"); // Добавляем в конец каждой строки <br />, // но не после </table>, </div>, </ol>, </ul>, <blockquote> (возможно внутри <span>) // и не в самом конце текста sb = _rxNewLines.Replace(sb, "<br />$0"); sb = _inlineTagReplacers.Aggregate(sb, (cur, replacer) => replacer(cur)); // Ссылки на MSDN. sb = _rxMsdn.Replace(sb, DoMSDNRef); // Нужно для отмены тэгов и отмены смайликов. sb = _rxPrep01.Replace(sb, ""); sb = _rxPrep02.Replace(sb, ""); sb = _rxPrep03.Replace(sb, ""); // restore & transform [code] tags for (var i = 0; i < codeMatcher.Count; i++) { // code coloring var code = PaintCode(codeMatcher[i]); // bold & italic formatting inside code // without checking canceling tag syntax code = _inlineTagReplacersNoChecks.Aggregate(code, (cur, replacer) => replacer(cur)); sb = sb.Replace(string.Format(codeExpression, i), code.ToString()); } return sb.ToString(); }