Как конвертировать Html в обычный текст?
У меня есть фрагменты Html, хранящиеся в таблице. не целые страницы, нет тегов или тому подобное, просто базовое форматирование.
Я хотел бы иметь возможность отображать этот Html только в виде текста, форматирование, на данной странице (на самом деле только первые 30 - 50 символов, но это самая легкая часть).
Как разместить "текст" в этом Html в строку как прямой текст?
Итак, этот кусок код.
<b>Hello World.</b><br/><p><i>Is there anyone out there?</i><p>
будет:
Привет Мир. Там кто-нибудь есть?
16 ответов:
Если вы говорите о зачистке тегов, это относительно прямолинейно, если вам не нужно беспокоиться о таких вещах, как
<script>
теги. Если все, что вам нужно сделать, это отобразить текст без тегов, вы можете сделать это с помощью регулярного выражения:<[^>]*>
Если вы должны беспокоиться о
<script>
теги и тому подобное, тогда вам понадобится что-то более мощное, чем регулярные выражения, потому что вам нужно отслеживать состояние, что-то больше похоже на контекстную грамматику (CFG). Хотя вы могли бы сделать это с помощью "слева направо" или не жадного сопоставления.Если вы можете использовать регулярные выражения есть много веб-страниц там с хорошей информацией:
- http://weblogs.asp.net/rosherove/archive/2003/05/13/6963.aspx
- http://www.google.com/search?hl=en&q=html+tag+stripping+&btnG=Search
Если вам нужно более сложное поведение CFG, я бы предложил используя сторонний инструмент, к сожалению, я не знаю хорошего, чтобы рекомендовать.
свободный и с открытым исходным кодом HtmlAgilityPack и в одном из своих образцов метод, который преобразует HTML в обычный текст.
var plainText = ConvertToPlainText(string html);
кормить его HTML-строку, как
Привет мир!
это я! !и вы получите простой текстовый результат, например:
hello world! it is me!
Я не мог использовать HtmlAgilityPack, поэтому я написал второе лучшее решение для себя
private static string HtmlToPlainText(string html) { const string tagWhiteSpace = @"(>|$)(\W|\n|\r)+<";//matches one or more (white space or line breaks) between '>' and '<' const string stripFormatting = @"<[^>]*(>|$)";//match any character between '<' and '>', even when end tag is missing const string lineBreak = @"<(br|BR)\s{0,1}\/{0,1}>";//matches: <br>,<br/>,<br />,<BR>,<BR/>,<BR /> var lineBreakRegex = new Regex(lineBreak, RegexOptions.Multiline); var stripFormattingRegex = new Regex(stripFormatting, RegexOptions.Multiline); var tagWhiteSpaceRegex = new Regex(tagWhiteSpace, RegexOptions.Multiline); var text = html; //Decode html specific characters text = System.Net.WebUtility.HtmlDecode(text); //Remove tag whitespace/line breaks text = tagWhiteSpaceRegex.Replace(text, "><"); //Replace <br /> with line breaks text = lineBreakRegex.Replace(text, Environment.NewLine); //Strip formatting text = stripFormattingRegex.Replace(text, string.Empty); return text; }
HTTPUtility.HTMLEncode()
предназначен для обработки HTML-тегов кодирования в виде строк. Он заботится обо всех тяжелых подъемных для вас. Из Примечание:если символы, такие как пробелы и знаки препинания передаются в потоке HTTP, они могут быть неверно истолкованы на принимающей стороне. Кодировка HTML преобразует символы, которые не разрешены в HTML, в эквиваленты символов-сущностей; декодирование HTML отменяет кодировку. Например, при внедрении в блок текст, символы
<
и>
, кодируются как<
и>
для передачи HTTP.
HTTPUtility.HTMLEncode()
метод, полная здесь:public static void HtmlEncode( string s, TextWriter output )
использование:
String TestString = "This is a <Test String>."; StringWriter writer = new StringWriter(); Server.HtmlEncode(TestString, writer); String EncodedString = writer.ToString();
чтобы добавить к ответу vfilby, вы можете просто выполнить регулярное выражение replace в своем коде; никаких новых классов не требуется. На случай, если другие новички, такие как я, наткнутся на этот вопрос.
using System.Text.RegularExpressions;
затем...
private string StripHtml(string source) { string output; //get rid of HTML tags output = Regex.Replace(source, "<[^>]*>", string.Empty); //get rid of multiple blank lines output = Regex.Replace(output, @"^\s*$\n", string.Empty, RegexOptions.Multiline); return output; }
в HtmlAgilityPack нет метода с именем "ConvertToPlainText", но вы можете преобразовать строку html в чистую строку с помощью :
HtmlDocument doc = new HtmlDocument(); doc.LoadHtml(htmlString); var textString = doc.DocumentNode.InnerText; Regex.Replace(textString , @"<(.|n)*?>", string.Empty).Replace(" ", "");
это работает для меня. Но я не нахожу метод с именем 'ConvertToPlainText' в 'HtmlAgilityPack'.
трехэтапный процесс преобразования HTML в обычный текст
сначала вам нужно установить пакет Nuget для HtmlAgilityPack Во-вторых создать этот класс
public class HtmlToText { public HtmlToText() { } public string Convert(string path) { HtmlDocument doc = new HtmlDocument(); doc.Load(path); StringWriter sw = new StringWriter(); ConvertTo(doc.DocumentNode, sw); sw.Flush(); return sw.ToString(); } public string ConvertHtml(string html) { HtmlDocument doc = new HtmlDocument(); doc.LoadHtml(html); StringWriter sw = new StringWriter(); ConvertTo(doc.DocumentNode, sw); sw.Flush(); return sw.ToString(); } private void ConvertContentTo(HtmlNode node, TextWriter outText) { foreach(HtmlNode subnode in node.ChildNodes) { ConvertTo(subnode, outText); } } public void ConvertTo(HtmlNode node, TextWriter outText) { string html; switch(node.NodeType) { case HtmlNodeType.Comment: // don't output comments break; case HtmlNodeType.Document: ConvertContentTo(node, outText); break; case HtmlNodeType.Text: // script and style must not be output string parentName = node.ParentNode.Name; if ((parentName == "script") || (parentName == "style")) break; // get text html = ((HtmlTextNode)node).Text; // is it in fact a special closing node output as text? if (HtmlNode.IsOverlappedClosingElement(html)) break; // check the text is meaningful and not a bunch of whitespaces if (html.Trim().Length > 0) { outText.Write(HtmlEntity.DeEntitize(html)); } break; case HtmlNodeType.Element: switch(node.Name) { case "p": // treat paragraphs as crlf outText.Write("\r\n"); break; } if (node.HasChildNodes) { ConvertContentTo(node, outText); } break; } } }
используя выше класс со ссылкой на ответ Иуды Химанго
В-третьих вам нужно создать объект выше класса и использовать
ConvertHtml(HTMLContent)
метод преобразования HTML в обычный текст, а неConvertToPlainText(string html);
HtmlToText htt=new HtmlToText(); var plainText = htt.ConvertHtml(HTMLContent);
у него есть ограничение, которое не разрушает длинные встроенные пробелы, но оно определенно портативно и уважает макет, такой как webbrowser.
static string HtmlToPlainText(string html) { string buf; string block = "address|article|aside|blockquote|canvas|dd|div|dl|dt|" + "fieldset|figcaption|figure|footer|form|h\d|header|hr|li|main|nav|" + "noscript|ol|output|p|pre|section|table|tfoot|ul|video"; string patNestedBlock = $"(\s*?</?({block})[^>]*?>)+\s*"; buf = Regex.Replace(html, patNestedBlock, "\n", RegexOptions.IgnoreCase); // Replace br tag to newline. buf = Regex.Replace(buf, @"<(br)[^>]*>", "\n", RegexOptions.IgnoreCase); // (Optional) remove styles and scripts. buf = Regex.Replace(buf, @"<(script|style)[^>]*?>.*?</>", "", RegexOptions.Singleline); // Remove all tags. buf = Regex.Replace(buf, @"<[^>]*(>|$)", "", RegexOptions.Multiline); // Replace HTML entities. buf = WebUtility.HtmlDecode(buf); return buf; }
Я думаю, что самый простой способ-сделать метод расширения "string" (основанный на том, что предложил пользователь Richard):
using System; using System.Text.RegularExpressions; public static class StringHelpers { public static string StripHTML(this string HTMLText) { var reg = new Regex("<[^>]+>", RegexOptions.IgnoreCase); return reg.Replace(HTMLText, ""); } }
тогда просто используйте этот метод расширения для любой переменной "string" в вашей программе:
var yourHtmlString = "<div class=\"someclass\"><h2>yourHtmlText</h2></span>"; var yourTextString = yourHtmlString.StripHTML();
Я использую этот метод расширения для преобразования html-форматированных комментариев в обычный текст, чтобы он правильно отображался в отчете crystal, и он отлично работает!
самый простой способ я нашел:
HtmlFilter.ConvertToPlainText(html);
класс HtmlFilter находится в Microsoft.TeamFoundation.Модуле.Контроли.dll
dll можно найти в папке, как это: %ProgramFiles%\Common Files\microsoft shared\Team Foundation Server\14.0\
в VS 2015 dll также требует Ссылки на Microsoft.TeamFoundation.Модуле.Общий.dll, находящаяся в той же папке.
Если у вас есть данные с тегами HTML, и вы хотите отобразить их так, чтобы человек мог видеть теги, используйте HttpServerUtility::HtmlEncode.
Если у вас есть данные, которые имеют теги HTML в нем, и вы хотите, чтобы пользователь видел теги отображаются, а затем отобразить текст как есть. Если текст представляет собой всю веб-страницу, используйте для него IFRAME.
Если у вас есть данные, которые имеют теги HTML, и вы хотите удалить теги и просто отобразить неформатированный текст, используйте обычный выражение.
зависит от того, что вы подразумеваете под "html."Самым сложным случаем были бы полные веб-страницы. Это также Самый простой в обращении, так как вы можете использовать текстовый веб-браузер. Смотрите статья в Википедии список веб-браузеров, включая браузеры, текстовый режим. Рысь, вероятно, самый известный, но один из других может быть лучше для ваших нужд.
вот мое решение:
public string StripHTML(string html) { var regex = new Regex("<[^>]+>", RegexOptions.IgnoreCase); return System.Web.HttpUtility.HtmlDecode((regex.Replace(html, ""))); }
пример:
StripHTML("<p class='test' style='color:red;'>Here is my solution:</p>"); // output -> Here is my solution:
у меня был тот же вопрос, просто мой html имел простой заранее известный макет, например:
<DIV><P>abc</P><P>def</P></DIV>
Так что я в конечном итоге с помощью такой простой код:
string.Join (Environment.NewLine, XDocument.Parse (html).Root.Elements ().Select (el => el.Value))
выходы:
abc def
не писал, но через:
using HtmlAgilityPack; using System; using System.IO; using System.Text.RegularExpressions; namespace foo { //small but important modification to class https://github.com/zzzprojects/html-agility-pack/blob/master/src/Samples/Html2Txt/HtmlConvert.cs public static class HtmlToText { public static string Convert(string path) { HtmlDocument doc = new HtmlDocument(); doc.Load(path); return ConvertDoc(doc); } public static string ConvertHtml(string html) { HtmlDocument doc = new HtmlDocument(); doc.LoadHtml(html); return ConvertDoc(doc); } public static string ConvertDoc(HtmlDocument doc) { using (StringWriter sw = new StringWriter()) { ConvertTo(doc.DocumentNode, sw); sw.Flush(); return sw.ToString(); } } internal static void ConvertContentTo(HtmlNode node, TextWriter outText, PreceedingDomTextInfo textInfo) { foreach (HtmlNode subnode in node.ChildNodes) { ConvertTo(subnode, outText, textInfo); } } public static void ConvertTo(HtmlNode node, TextWriter outText) { ConvertTo(node, outText, new PreceedingDomTextInfo(false)); } internal static void ConvertTo(HtmlNode node, TextWriter outText, PreceedingDomTextInfo textInfo) { string html; switch (node.NodeType) { case HtmlNodeType.Comment: // don't output comments break; case HtmlNodeType.Document: ConvertContentTo(node, outText, textInfo); break; case HtmlNodeType.Text: // script and style must not be output string parentName = node.ParentNode.Name; if ((parentName == "script") || (parentName == "style")) { break; } // get text html = ((HtmlTextNode)node).Text; // is it in fact a special closing node output as text? if (HtmlNode.IsOverlappedClosingElement(html)) { break; } // check the text is meaningful and not a bunch of whitespaces if (html.Length == 0) { break; } if (!textInfo.WritePrecedingWhiteSpace || textInfo.LastCharWasSpace) { html = html.TrimStart(); if (html.Length == 0) { break; } textInfo.IsFirstTextOfDocWritten.Value = textInfo.WritePrecedingWhiteSpace = true; } outText.Write(HtmlEntity.DeEntitize(Regex.Replace(html.TrimEnd(), @"\s{2,}", " "))); if (textInfo.LastCharWasSpace = char.IsWhiteSpace(html[html.Length - 1])) { outText.Write(' '); } break; case HtmlNodeType.Element: string endElementString = null; bool isInline; bool skip = false; int listIndex = 0; switch (node.Name) { case "nav": skip = true; isInline = false; break; case "body": case "section": case "article": case "aside": case "h1": case "h2": case "header": case "footer": case "address": case "main": case "div": case "p": // stylistic - adjust as you tend to use if (textInfo.IsFirstTextOfDocWritten) { outText.Write("\r\n"); } endElementString = "\r\n"; isInline = false; break; case "br": outText.Write("\r\n"); skip = true; textInfo.WritePrecedingWhiteSpace = false; isInline = true; break; case "a": if (node.Attributes.Contains("href")) { string href = node.Attributes["href"].Value.Trim(); if (node.InnerText.IndexOf(href, StringComparison.InvariantCultureIgnoreCase) == -1) { endElementString = "<" + href + ">"; } } isInline = true; break; case "li": if (textInfo.ListIndex > 0) { outText.Write("\r\n{0}.\t", textInfo.ListIndex++); } else { outText.Write("\r\n*\t"); //using '*' as bullet char, with tab after, but whatever you want eg "\t->", if utf-8 0x2022 } isInline = false; break; case "ol": listIndex = 1; goto case "ul"; case "ul": //not handling nested lists any differently at this stage - that is getting close to rendering problems endElementString = "\r\n"; isInline = false; break; case "img": //inline-block in reality if (node.Attributes.Contains("alt")) { outText.Write('[' + node.Attributes["alt"].Value); endElementString = "]"; } if (node.Attributes.Contains("src")) { outText.Write('<' + node.Attributes["src"].Value + '>'); } isInline = true; break; default: isInline = true; break; } if (!skip && node.HasChildNodes) { ConvertContentTo(node, outText, isInline ? textInfo : new PreceedingDomTextInfo(textInfo.IsFirstTextOfDocWritten) { ListIndex = listIndex }); } if (endElementString != null) { outText.Write(endElementString); } break; } } } internal class PreceedingDomTextInfo { public PreceedingDomTextInfo(BoolWrapper isFirstTextOfDocWritten) { IsFirstTextOfDocWritten = isFirstTextOfDocWritten; } public bool WritePrecedingWhiteSpace { get; set; } public bool LastCharWasSpace { get; set; } public readonly BoolWrapper IsFirstTextOfDocWritten; public int ListIndex { get; set; } } internal class BoolWrapper { public BoolWrapper() { } public bool Value { get; set; } public static implicit operator bool(BoolWrapper boolWrapper) { return boolWrapper.Value; } public static implicit operator BoolWrapper(bool boolWrapper) { return new BoolWrapper { Value = boolWrapper }; } } }