解析HTML以修复微型排版和字形问题。

20

我对网络上的微排版问题很感兴趣。

我想要一个工具来解决:

  • 引号
    • “(“)开头引号(而不是“)
    • ”(”)结束引号(而不是“)
  • 撇号
    • ’(’)撇号(而不是')
  • 破折号和连字符
    • –(–或–)短划线,用于范围,例如“11月13日至15日”(而不是-)
    • —(—或—)长划线,用于思路转变,例如“众所周知,星球大战是——惊人的。”(而不是-或--)
  • 省略号
    • …(…或…)水平省略号,用于表示省略或暂停(而不是...)
  • 还有更多 \o/
All those fixes depend on the content language. In French, for example, we must add a non-breaking space before every composed glyph (:, ;, …, ?, !, ...), and our quotes are « like this ».
There are many constraints for such a tool:
- it must not edit any HTML inside protected tags (pre, code...) - it must be fast (used on a CMS output) - it must not break the HTML - and so on.
There already are some tools on the market: 他们都或多或少基于SmartyPants,这是一个2005年的库,未经测试、未经文档化,手动解析HTML并且没有处理英语以外的规则。太糟糕了。
那么我的问题是:
  • 您是否知道类似于此的任何体面工具?
  • 我该如何做呢?我已经有一个使用DomCrawler的POC,但我不确定。在PHP中解析和编辑HTML的最佳方法是什么?

2013年7月更新: 我从这个问题中获得的测试和专业知识,开发了JoliTypo。没有现有的库能够满足我的需求。

6
好问题,不过我在想,这种事情是不是最好在数据保存的时候处理,而不是输出的时候处理呢?特别是当你有大量文本时(这种情况下这将是最有用的),很难想象以一种高效的方式进行详细处理(比如区分适当使用短横线和长横线),以使其不会极大地增加页面加载时间。 - Michael Schuller
3
我认为这应该由缓存系统处理。我认为编辑用户提交的内容并使其持久化是一个不好的想法,因为无法恢复打字版本。对于性能相关问题,存储用户和转换后的文本都可以是一种解决方案。 - Damien
1
当然,这样做会使输出与输入之间的关系对于输入原始文本的用户有些不透明的风险,但我想那是一个哲学问题,而不是技术问题。我认为像Markdown这样的东西之所以成为格式化文本输入的好解决方案之一,是因为你知道将应用哪些转换(并且你可以像输入时一样恢复原始文本)。 - Michael Schuller
也许可以考虑使用Perl正则表达式进行替换。我可以为您编写一些代码[http://php.net/manual/ru/intro.pcre.php]。 - MaxXx1313
我的最佳猜测是一系列函数,它们会在执行时具有内容感知能力,在执行任何操作之前进行一些检查。WordPress 在我看来以一种肮脏的方式实现了这一点,但它尽力使替换变得更好,也许你可以从它们的源代码中受益。即使你想避免,每种语言都有自己的特殊性,你无法逃避这一点。 - pocesar
2
不要使用正则表达式解析HTML,这样做是不可靠的。请使用适当的DOM解析器。 - Andy Lester
4个回答

8

很好,谢谢!它在 Github 上,有单元测试,我很开心。但是它使用正则表达式解析 HTML,这让我想起了这篇博客文章:http://www.codinghorror.com/blog/2009/11/parsing-html-the-cthulhu-way.html无论如何,我会留意并尝试一下 - 但对我来说似乎不是万无一失的。 - Damien
1
正如文章所指出的那样,在许多简单情况下,使用正则表达式之类的东西比使用完整的HTML引擎更明智。在这种情况下,代码旨在处理其http://phpadvent.org网站上的文章。您想要在CMS输出的内容部分上运行它的特定情况似乎是匹配的。此外:这是我唯一得到的解决方案。 - preinheimer
基于正则表达式的解决方案应用于文本字符串级别是正确的解决方案。谢谢帮助,Lexentity 是我能得到的最佳起点。享受这份奖励吧;-) - Damien
感谢@Damien,Sean对改进非常敏锐,所以如果您继续使用新语言等进行更深入的开发,请提交拉取请求 :) - preinheimer
@Damien,它使用正则表达式生成标记,而不是完全解析HTML。许多(大多数?)词法分析器使用正则表达式将源代码解析为标记。我完全同意不应该使用正则表达式解析HTML,但这并不相同。 - scoates

2
你可能会对tidy感兴趣。它与PHP 5+捆绑在一起(你只需要使用libtidy即可)。它不仅解析HTML,还可以修复它。
但是,在本地化方面,你需要自己解决 - intl没有任何关于引号的数据-例如; 至少我找不到。

2

关于引用,请参考Q标签,对于其他情况,我会使用bbcode库。 由于很难编写算法来区分您需要的破折号。BBcode允许编辑器进行选择,但在这种情况下,当编辑器需要执行某个操作时,您可以考虑提供一种按钮来插入特殊字符。 对于易于识别的内容,您只需为BBcode库创建新规则,如果它们需要本地化,则可以为不同语言创建不同的规则集。显然,面向对象编程中的继承在这里非常方便。


2
如其他人所说,基于正则表达式的解决方案可能会有危险/被禁止...但是,如果你对想要在此工具上使用的内容进行了封锁(如果内容来自你的 CMS,那么听起来就像是),那么 Perl 程序 Demoroniser 的扩展似乎可以为您解决这个问题:http://www.fourmilab.ch/webtools/demoroniser/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接