【发布时间】:2015-09-04 18:14:56
【问题描述】:
主要是当我们缩短/截断文本内容时,我们通常只是在特定字符索引处截断它。无论如何,这在 HTML 中已经很复杂了,但我想使用不同的措施截断我的 HTML 内容(使用 content-editable div 生成):
- 我将定义字符索引
N作为截断起点limit - 算法将检查内容是否至少有
N个字符长(仅文本;不计算标签);如果不是,它只会返回整个内容 - 然后它将检查从
N-X到N+X的字符位置(仅限文本)并搜索块节点的结尾;X是预定义的 offset 值,可能约为N/5到N/4; - 如果有多个区块节点在此范围内结束,算法将选择最接近限制索引
N的结束节点 - 如果没有块节点在此范围内结束,它将在同一范围内找到最近的单词边界并选择最接近
N的索引并在该位置截断。 - 返回带有有效 HTML 的截断内容(所有标签都在末尾关闭)
我的内容可编辑生成的内容可能包含段落(带有换行符)、预先格式化的代码块、块引号、有序和无序列表、标题、粗体和斜体(它们是内联节点,不应计入截断过程)等等。最终的实现当然会定义哪些元素具体是可能的截断候选者。标题即使是块 HTML 元素也不会算作截断点,因为我们不想要寡居的标题。段落、列出单个项目、整个有序和无序列表、块引用、预格式化块、空元素等都是很好的。标题和所有内联块元素都不是。
示例
让我们以这个 stackoverflow 问题作为我想要截断的 HTML 内容的示例。让我们将截断限制设置为 1000,偏移量为 250 个字符 (1/4)。
This DotNetFiddle 显示此问题的文本,同时还在其中添加限制标记(|MIN| 表示字符 750,|LIMIT| 表示字符 1000 和 |MAX| 表示字符 1250)。
从示例中可以看出两个块节点之间最接近的截断边界到字符 1000 是在 </OL> 和 P 之间(我的内容可编辑生成... em>)。这意味着我的 HTML 应该在这两个标签之间被截断,这将导致内容文本长度少于 1000 个字符,但保持截断的内容有意义,因为它不会只是截断某些文本段落中间的某个位置。
我希望这能解释与此算法相关的事情应该如何工作。
问题
我在这里看到的第一个问题是我正在处理像 HTML 这样的嵌套结构。我还必须检测不同的元素(只有块元素,没有内联元素)。最后但并非最不重要的一点是,我必须只计算字符串中的某些字符并忽略那些属于标签的字符。
可能的解决方案
- 我可以通过创建一些表示内容节点及其层次结构的对象树来手动解析我的内容
- 我可以将 HTML 转换为更易于管理的内容,例如 markdown,然后只需搜索最接近我提供的索引
N的新行并转换回 HTML - 使用 HTML Agility Pack 之类的东西并用它替换我的 #1 解析,然后以某种方式使用 XPath 提取块节点并截断内容
第二个想法
- 我确信我可以通过执行 #1 来做到这一点,但感觉我是在重新发明轮子。
- 我认为 #2 没有任何 C# 库,因此我也应该手动将 HTML 转换为 Markdown,或者将 pandoc 作为外部进程运行。
- 我可以使用 HAP,因为它在处理 HTML 方面非常出色,但我不确定使用它是否足够简单。恐怕我的自定义代码中的大部分处理仍将在 HAP 之外
应该如何处理这种截断算法?我的脑袋似乎太累了,无法达成共识(或解决方案)。
【问题讨论】:
-
当然没有灵丹妙药,但我会使用 HAP,HAP 可以通过一个 xpath 获取所有文本:
//text()。然后,每个节点还有一个XPath属性,因此您可以从这些文本元素来回遍历树。使用InnerHtml属性可以很容易地更改这些文本元素内容。最后,HAP 会在输出 HTML 时自动关闭未关闭的元素。 -
@SimonMourier:想在答案中显示一些代码吗?
-
你有一些示例输入和预期输出吗?
-
抱歉,我想说点题外话。重新发明轮子没有错,如果你认为你可以让它变得更好或更简单,为什么不呢?毕竟,我们是从几个世纪前的木轮中找到我们现在的轮子的,:p