gpt4 book ai didi

c# - 全部的 HtmlAgilityPack 子串按长度

转载 作者:太空宇宙 更新时间:2023-11-03 21:52:32 24 4
gpt4 key购买 nike

我有嵌套元素的 html(主要是 divp 元素)我需要返回相同的 html,但由给定数量的字母进行子字符串化。显然字母数不应该通过html标签来枚举,而是只统计每个html元素的InnerText的字母数。Html 结果应保留正确的结构 - 任何结束标记以保持有效的 html。

示例输入:

<div>
<p>some text</p>
<p>some more text some more text some more text some more text some more text</p>
<div>
<p>some more text some more text some more text some more text some more text</p>
<p>some more text some more text some more text some more text some more text</p>
</div>
</div>

给定int length = 16输出应如下所示:

<div>
<p>some text</p> // 9 characters in the InnerText here
<p>some mo</p> // 7 characters in the InnerText here; 9 + 7 = 16;
</div>

注意字母(包括空格)的个数是16。后面的<div>由于字母计数已达到变量 length 而被消除.请注意,输出 html 仍然有效。

我已经尝试了以下方法,但这并不奏效。输出不符合预期:某些 html 元素重复出现。

public static string SubstringHtml(this string html, int length)
{
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(html);
int totalLength = 0;
StringBuilder output = new StringBuilder();
foreach (var node in doc.DocumentNode.Descendants())
{
totalLength += node.InnerText.Length;
if(totalLength >= length)
{
int difference = totalLength - length;
string lastPiece = node.InnerText.ToString().Substring(0, difference);
output.Append(lastPiece);
break;
}
else
{
output.Append(node.InnerHtml);
}
}
return output.ToString();
}

更新

@SergeBelov 提供了一个适用于第一个样本输入的解决方案,但是进一步的测试显示了一个与下面的输入类似的问题。

示例输入#2:

some more text some more text 
<div>
<p>some text</p>
<p>some more text some more text some more text some more text some more text</
</div>

给定变量 int maxLength = 7;输出应该等于some mo。它不像那样工作,因为这段代码在哪里 ParentNode = null :

lastNode
.Node
.ParentNode
.ReplaceChild(HtmlNode.CreateNode(lastNodeText.InnerText.Substring(0, lastNode.NodeLength - lastNode.TotalLength + maxLength)), lastNode.Node);

创建一个新的 HtmlNode 似乎没有帮助,因为它的 InnterText 属性是只读的。

最佳答案

下面的小型控制台程序说明了一种可能的方法,即:

  1. 选择相关的文本节点并计算它们的运行总长度;
  2. 根据需要获取尽可能多的节点,使运行总数超过最大长度;
  3. 从文档中删除所有元素节点,但我们在步骤 ##1、2 中选择的节点的祖先节点除外;
  4. 剪切列表最后一个节点中的文本以适应最大长度。

更新:这应该仍然适用于第一个文本节点;可能需要一个 Trim() 来从中删除空格,如下所示。

    static void Main(string[] args)
{
int maxLength = 9;
string input = @"
some more text some more text
<div>
<p>some text</p>
<p>some more text some more text some more text some more text some more text</
</div>";

var doc = new HtmlDocument();
doc.LoadHtml(input);

// Get text nodes with the appropriate running total
var acc = 0;
var nodes = doc.DocumentNode
.Descendants()
.Where(n => n.NodeType == HtmlNodeType.Text && n.InnerText.Trim().Length > 0)
.Select(n =>
{
var length = n.InnerText.Trim().Length;
acc += length;
return new { Node = n, TotalLength = acc, NodeLength = length };
})
.TakeWhile(n => (n.TotalLength - n.NodeLength) < maxLength)
.ToList();

// Select element nodes we intend to keep
var nodesToKeep = nodes
.SelectMany(n => n.Node.AncestorsAndSelf()
.Where(m => m.NodeType == HtmlNodeType.Element));

// Select and remove element nodes we don't need
var nodesToDrop = doc.DocumentNode
.Descendants()
.Where(m => m.NodeType == HtmlNodeType.Element)
.Except(nodesToKeep)
.ToList();

foreach (var r in nodesToDrop)
r.Remove();

// Shorten the last node as required
var lastNode = nodes.Last();
var lastNodeText = lastNode.Node;
var text = lastNodeText.InnerText.Trim().Substring(0,
lastNode.NodeLength - lastNode.TotalLength + maxLength);
lastNodeText
.ParentNode
.ReplaceChild(HtmlNode.CreateNode(text), lastNodeText);

doc.Save(Console.Out);
}

关于c# - 全部的 HtmlAgilityPack 子串按长度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13793129/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com