我在一个表格中存储了一些Html片段。不是整页,没有标签或类似的东西,只有基本格式。
我想要能够仅作为文本显示该Html,在给定页面上没有格式(实际上只需前30-50个字符,但那很容易)。
我如何将Html中的“文本”作为纯文本放入字符串中?
因此,这段代码。
<b>Hello World.</b><br/><p><i>Is there anyone out there?</i><p>
变成:
你好,世界。有人在吗?
我在一个表格中存储了一些Html片段。不是整页,没有标签或类似的东西,只有基本格式。
我想要能够仅作为文本显示该Html,在给定页面上没有格式(实际上只需前30-50个字符,但那很容易)。
我如何将Html中的“文本”作为纯文本放入字符串中?
因此,这段代码。
<b>Hello World.</b><br/><p><i>Is there anyone out there?</i><p>
变成:
你好,世界。有人在吗?
使用MIT许可的HtmlAgilityPack库,在其示例代码中包含一种将HTML转换为纯文本的方法。
var plainText = HtmlUtilities.ConvertToPlainText(string html);
将HTML字符串作为参数传递给它,例如:
<b>hello, <i>world!</i></b>
你将获得一个纯文本结果,如下所示:
hello world!
我不能使用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;
}
如果您在谈论标签剥离,那么如果您不必担心像 <script>
标签这样的东西,这相对来说是相当简单的。如果你只需要显示文本而没有标签,你可以使用正则表达式来实现:
<[^>]*>
如果你需要担心<script>
标签等问题,那么你需要使用比正则表达式更强大的东西来跟踪状态,例如上下文无关文法(CFG),虽然你可能可以用“从左到右”或非贪婪匹配来实现。
如果你可以使用正则表达式,那么有许多网页提供了很好的信息:
如果您需要CFG的更复杂行为,我建议使用第三方工具,不幸的是我不知道推荐一个好的工具。
HTTPUtility.HTMLEncode()
方法的作用是将HTML标签编码为字符串。它将为您处理所有繁琐的工作。根据MSDN文档的说明:
如果在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();
将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;
}
}
}
通过参考Judah Himango的答案,您可以使用上述类。
第三步,您需要创建上述类的对象,并使用ConvertHtml(HTMLContent)
方法将HTML转换为纯文本,而不是ConvertToPlainText(string html);
HtmlToText htt=new HtmlToText();
var plainText = htt.ConvertHtml(HTMLContent);
除了vfilby的回答,你可以在你的代码中进行正则表达式替换;不需要新的类。如果其他像我一样的新手遇到这个问题。
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;
}
更新2023年的答案。答案基本上与以往相同:
安装最新的HtmlAgilityPack
创建一个名为HtmlUtilities的实用程序类,该类使用HtmlAgilityPack。
使用它:var plainText = HtmlUtilities.ConvertToPlainText(email.HtmlCode);
以下是从上面链接中复制的HtmlUtilities类:
using HtmlAgilityPack;
using System;
using System.IO;
namespace ReadSharp
{
public class HtmlUtilities
{
/// <summary>
/// Converts HTML to plain text / strips tags.
/// </summary>
/// <param name="html">The HTML.</param>
/// <returns></returns>
public static string ConvertToPlainText(string html)
{
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(html);
StringWriter sw = new StringWriter();
ConvertTo(doc.DocumentNode, sw);
sw.Flush();
return sw.ToString();
}
/// <summary>
/// Count the words.
/// The content has to be converted to plain text before (using ConvertToPlainText).
/// </summary>
/// <param name="plainText">The plain text.</param>
/// <returns></returns>
public static int CountWords(string plainText)
{
return !String.IsNullOrEmpty(plainText) ? plainText.Split(' ', '\n').Length : 0;
}
public static string Cut(string text, int length)
{
if (!String.IsNullOrEmpty(text) && text.Length > length)
{
text = text.Substring(0, length - 4) + " ...";
}
return text;
}
private static void ConvertContentTo(HtmlNode node, TextWriter outText)
{
foreach (HtmlNode subnode in node.ChildNodes)
{
ConvertTo(subnode, outText);
}
}
private static 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;
case "br":
outText.Write("\r\n");
break;
}
if (node.HasChildNodes)
{
ConvertContentTo(node, outText);
}
break;
}
}
}
}
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)[^>]*?>.*?</\1>", "", RegexOptions.Singleline);
// Remove all tags.
buf = Regex.Replace(buf, @"<[^>]*(>|$)", "", RegexOptions.Multiline);
// Replace HTML entities.
buf = WebUtility.HtmlDecode(buf);
return buf;
}
XDocument
发布一段代码。 - jeiea我认为最简单的方法是创建一个“字符串”扩展方法(基于用户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, "");
}
}
在您的程序中,只需对任何“字符串”变量使用此扩展方法:
var yourHtmlString = "<div class=\"someclass\"><h2>yourHtmlText</h2></span>";
var yourTextString = yourHtmlString.StripHTML();
我使用这个扩展方法将HTML格式的评论转换为纯文本,以便在Crystal报表上正确显示,它运行得非常完美!
HtmlFilter.ConvertToPlainText(html);
HtmlFilter类位于Microsoft.TeamFoundation.WorkItemTracking.Controls.dll中。
该dll可以在以下文件夹中找到: %ProgramFiles%\Common Files\microsoft shared\Team Foundation Server\14.0\
在VS 2015中,该dll还需要引用位于同一文件夹中的Microsoft.TeamFoundation.WorkItemTracking.Common.dll。