【问题标题】:Normalizing Unicode according to the W3C in PHP在 PHP 中根据 W3C 规范化 Unicode
【发布时间】:2023-03-20 11:23:01
【问题描述】:

W3C validator 中验证我网站的 HTML 代码时,我收到以下警告:

Line 157, Column 220: Text run is not in Unicode Normalization Form C.

…i͈̭̋ͥ̂̿̄̋̆ͣv̜̺̋̽͛̉͐̀͌̚e͖̼̱ͣ̓ͫ͆̍̄̍͘-̩̬̰̮̯͇̯͆̌ͨ́͌ṁ̸͖̹͎̱̙̱͟͡i̷̡͌͂͏̘̭̥̯̟n̏͐͌̑̄̃͘͞…

我在 PHP 5.3.x 中开发它,所以我可以使用 Normalizer 类。

所以,为了解决这个问题,我应该在显示用户的任何输入(例如评论)时使用Normalizer::normalize($output),还是应该在将任何用户输入存储到数据库之前使用Normalizer::normalize($input)

tl;dr:我应该在将用户输入存储到数据库之前还是仅在显示时使用Unicode normalization

【问题讨论】:

  • 您在页面上显示什么样的数据?这似乎更像是验证器的问题,而不是您的数据。
  • 用户可以合法发布的 this 之类的内容。这只是一堆看起来很糟糕的带有很多上标和下标的文本。
  • 有趣 :) 我确定验证器会因某种字符组合而中断...但我也发现了这个线程 comments.gmane.org/gmane.org.w3c.validator/13243
  • 感谢链接人,我不知道这是一个如此复杂的主题。我想我会正常化一切以防万一。只要验证器高兴,导航器也应该如此
  • 是的,这个话题没完没了... :-)

标签: php unicode normalization web-standards unicode-normalization


【解决方案1】:

严格来说,Web 字符模型的规则不仅仅是规范化为 NFC,而且任何包含来自其他机制的文本的技术运行之前和之后的表单都应该在 NFC 中。例如 XML 包含、字符引用和实体引用。例如,ä 不适合字符模型,因为它在 NFC 中扩展字符引用会将其转换为 a,然后是组合 diareses,这不是 NFC。大多数情况下,避免这种情况在实践中很容易,但值得注意。

U+0338 有一个有趣的例子。 > 后跟 U+0338 归一化为 并使用 < 生成 。为什么不允许它出现在元素名称的开头或作为元素中的第一个字符的原因应该很清楚。

作为一项规则,在任何情况下,让一段文本以组合字符开头是没有意义的,但是这个特殊的例子允许整个文档被破坏(即使你不规范化,因为其他东西可能)。

如果您只关心作为文本的文本(例如,对数字签名不感兴趣),那么对输入进行规范化可以简化您的其余工作,包括您对文本的内部使用(例如搜索),所以可能是要走的路。

请参阅http://www.w3.org/TR/charmod-norm/ 了解更多信息。

【讨论】:

    【解决方案2】:

    您可以根据应用程序的目的和性质来决定是在读取用户输入时应用规范化,还是将其存储到数据库中,或者在编写时应用规范化,或者根本不应用。总结一下cmets中提到的长线程问题,也可以在http://validator.w3.org/feedback.html的官方列表存档中找到

    • 警告消息来自实验性的“HTML5 验证”(这实际上是一个 linter,除了一些正式的测试之外还应用主观规则)。
    • 该消息并非基于 HTML5 草案中的任何要求,而是基于对可能导致某些软件出现问题的原因的意见。
    • 最初使“HTML5 验证”发出错误消息的意见,现在是警告。

    将非规范化数据作为用户输入当然是可能的,尽管不常见。这不取决于浏览器执行的规范化(它们不做这些事情,尽管他们可以想象将来可能会这样做),而是取决于输入方法和习惯。例如,键入字母 ü(u 变音符号,或带分音符号的 u)的方法往往会按照规范化的方式生成预先组合形式的字符。人们可以将其生成为非规范化的分解形式,如字母 u 后跟分音符号,但他们通常没有理由这样做,而且大多数人甚至不知道该怎么做。

    如果您在软件中进行字符串比较,它们可能会或可能不会(取决于使用的比较例程)处理例如a precomposed ü 等于分解后的表示。简单实现将它们视为不同,因为它们在简单字符级别(Unicode 代码点)绝对不同。

    最迟在写作阶段进行规范化的一个原因是,预先组合的字符通常会更可靠地显示。要呈现规范化的 ü,程序只需从字体中提取字形。要呈现分解的 ü,程序必须要么将其识别为规范化的 ü,要么在字母 u 上适当放置分音符号,并适当注意 u 字形的图形属性,许多程序会失败在这。

    另一方面,在极少数情况下,接收到非规范化数据作为用户输入,用户很可能有理由生成它。他可能认为规范化的 ü 和非规范化的 ü 是不同的,需要这样对待。

    【讨论】:

    • 很好的答案,非常详细和深思熟虑。但是,我不同意最后一段......如果输入字母 ü 的两种方法(无论是 u 变音符号还是带分音符号的 u)都导致 ü - 完全相同的字符,没有人类可见的差异 - 为什么把它们当作不同的东西?我在这里可能错了,但这难道不是一个使用规范化应该的完美例子吗?
    • 作为文本,它们应该被认为是等价的。如果有操作也将它们视为八位字节,那么它们不能。一个例子是如果他们有一个数字签名——规范化会改变它,使它不再是被签名的东西。这就是 XML 签名在实际签名中具有规范化步骤的原因,因此它只会被 NFC 签名。当输出为 HTML 时,它将作为文本输出,这无关紧要,因此它仍然应该是 NFC,但您可能有理由保留发送的表单。
    • @John Doe,它们不会产生相同的字符,而是产生一个字符和一个两个字符的序列,它们在规范上是等效的。规范等价不是一种身份,而可能处理的程序可以。等价的字符是不同的,尽管我们不应该期望程序这样做。由于我提到的渲染机制(例如,通过直接使用字形显示预先组合的 ü,但通过使用“u”字形并在其上放置“¨”来显示分解的 ü,规范等价甚至并不意味着视觉识别——有时甚至采用其他字体的变音符号!)。
    • 我相信关于编码、用户输入和 utf8 的许多不同知识使这个答案成为我读过的关于 utf8 的信息最丰富的一篇文章。
    猜你喜欢
    • 2014-09-03
    • 2013-05-04
    • 1970-01-01
    • 2019-03-27
    • 2011-12-08
    • 2011-10-25
    相关资源
    最近更新 更多