关于如何剥离html标签有很多问题,但关于它们的函数/方法并不多。
这是情况。我有一个500字符的消息摘要(包括html标签),但我只想要前100个字符。问题是如果我截断消息,它可能在html标签的中间......这会弄乱一些东西。
假设html是这样的:
<div class="bd">"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. <br/>
<br/>Some Dates: April 30 - May 2, 2010 <br/>
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. <em>Duis aute irure dolor in reprehenderit</em> in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. <br/>
</p>
For more information about Lorem Ipsum doemdloe, visit: <br/>
<a href="http://www.somesite.com" title="Some Conference">Some text link</a><br/>
</div>
我如何拍摄前100个字符左右? (虽然理想情况下,这将是“CONTENT”的第一个大约100个字符(在html标签之间)
我假设最好的方法是使用递归算法来跟踪html标签并附加任何会被截断的标签,但这可能不是最好的方法。
我的第一个想法是使用递归来计算嵌套标签,当我们达到100个字符时,查找下一个“&lt;”然后使用递归来编写那里所需的结束html标记。
这样做的原因是对现有文章做一个简短的总结,而不要求用户返回并提供所有文章的摘要。如果可能的话,我想保留html格式。
注意:请忽略html不是完全语义的。这是我必须从我的WYSIWYG处理的事情。
我添加了一个潜在的解决方案(似乎有效)我认为其他人也会遇到这个问题。我不确定它是最好的...而且它可能不是非常强大(事实上,我知道它不是),但我很感激任何反馈
答案 0 :(得分:4)
这是大多数情况下的解决方案。它不处理不正确的html标签,以及诸如“a&lt; b&gt; c”的情况。但它适用于我的目的,也许对其他人有帮助。
/// <summary>
/// Gets first number of characters from the html string without stripping tags
/// </summary>
/// <param name="htmlString">The html string, not encoded, pure html</param>
/// <param name="length">The number of first characters to get</param>
/// <returns>The html string</returns>
public static string GetFirstCharacters(string htmlString, int length)
{
if (htmlString == null)
return string.Empty;
if(htmlString.Length < length)
return htmlString;
// regex to separate string on parts: tags, texts
var separateRegex = new Regex("([^>][^<>]*[^<])|[\\S]{1}");
// regex to identify tags
var tagsRegex = new Regex("^<[^>]+>$");
// separate string on tags and texts
var matches = separateRegex.Matches(htmlString);
// looping by mathes
// if it's a tag then just append it to resuls,
// if it's a text then append substing of it (considering the number of characters)
var counter = 0;
var sb = new StringBuilder();
for (var i = 0; i < matches.Count; i++)
{
var m = matches[i].Value;
// check if it's a tag
if (tagsRegex.IsMatch(m))
{
sb.Append(m);
}
else
{
var lengthToCut = length - counter;
var sub = lengthToCut >= m.Length
? m
: m.Substring(0, lengthToCut);
counter += sub.Length;
sb.Append(sub);
}
}
return sb.ToString();
}
答案 1 :(得分:3)
如果您将HTML解析为DOM结构,然后开始遍历广度优先或深度优先,无论您喜欢什么,收集节点文本直到达到100个字符?
答案 2 :(得分:1)
过去我用正则表达式完成了这个。抓取内容,通过正则表达式删除标签,然后将其修剪到所需的长度。
当然,这会删除所有HTML,这就是我想要的。如果你想保留HTML,我会考虑不关闭开放标签,而是删除开放标签。
答案 3 :(得分:1)
我的建议是找到一个HTML友好的遍历器(允许你像XML一样遍历HTML),然后从头开始标签忽略标签本身,只计算标签中的数据。计算到你的极限,然后一旦达到关闭每个标签(我不能想到任何不仅仅是标签的标签)。
这应该运作得相当好,并且与您正在寻找的相当接近。
它完全脱离了ol'noggin的顶部所以我假设会有一些棘手的部分,比如显示的属性值(例如链接标记值)。
答案 4 :(得分:1)
我决定推出自己的解决方案......只是为了应对挑战。
如果有人能看到任何逻辑错误或效率低下,请告诉我。
我不知道这是否是最好的方法......但似乎有效。有可能它不起作用的情况......如果html不正确,它可能会失败。
/// <summary>
/// Get the first n characters of some html text
/// </summary>
private string truncateTo(string s, int howMany, string ellipsis) {
// return entire string if it's more than n characters
if (s.Length < howMany)
return s;
Stack<string> elements = new Stack<string>();
StringBuilder sb = new StringBuilder();
int trueCount = 0;
for (int i = 0; i < s.Length; i++) {
if (s[i] == '<') {
StringBuilder elem = new StringBuilder();
bool selfclosing = false;
if (s[i + 1] == '/') {
elements.Pop(); // Take the previous element off the stack
while (s[i] != '>') {
i++;
}
}
else { // not a closing tag so get the element name
while (i < s.Length && s[i] != '>') {
if ((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A' && s[i] <= 'Z')) {
elem.Append(s[i]);
}
else if (s[i] == '/' || s[i] == ' ') {
// self closing tag or end of tag name. Find the end of tag
do {
if (s[i] == '/' && s[i + 1] == '>') {
// at the end of self-closing tag. Don't store
selfclosing = true;
}
i++;
} while (i < s.Length && s[i] != '>');
}
i++;
} // end while( != '>' )
if (!selfclosing)
elements.Push(elem.ToString());
}
}
else {
trueCount++;
if (trueCount > howMany) {
sb.Append(s.Substring(0, i - 1));
sb.Append(ellipsis);
while (elements.Count > 0) {
sb.AppendFormat("</{0}>", elements.Pop());
}
}
}
}
return sb.ToString();
}
答案 5 :(得分:0)
我使用了XmlReader和XmlWriter来执行此操作: https://gist.github.com/2413598
正如其他人所说,您应该使用SgmlReader或HtmlAgilityPack来对传入的字符串进行处理。
答案 6 :(得分:0)
我明白了你的问题。在do while循环中有一个错误:
} while (i < s.Length && s[i] != '>');
应替换为
} while (i < s.Length && ***s[i+1]*** != '>');