规范化 Unicode

Posted

技术标签:

【中文标题】规范化 Unicode【英文标题】:Normalizing Unicode 【发布时间】:2013-05-04 06:22:31 【问题描述】:

在 Python 中是否有标准方法来规范化 unicode 字符串,以便它只理解可用于表示它的最简单的 unicode 实体?

我的意思是,可以将['LATIN SMALL LETTER A', 'COMBINING ACUTE ACCENT'] 之类的序列转换为['LATIN SMALL LETTER A WITH ACUTE']

看看问题出在哪里:

>>> import unicodedata
>>> char = "á"
>>> len(char)
1
>>> [ unicodedata.name(c) for c in char ]
['LATIN SMALL LETTER A WITH ACUTE']

但是现在:

>>> char = "á"
>>> len(char)
2
>>> [ unicodedata.name(c) for c in char ]
['LATIN SMALL LETTER A', 'COMBINING ACUTE ACCENT']

当然,我可以遍历所有字符并进行手动替换等,但效率不高,而且我很确定我会错过一半的特殊情况并犯错误。

【问题讨论】:

【参考方案1】:

unicodedata 模块提供了一个.normalize() function,您希望标准化为 NFC 表单。使用相同的 U+0061 LATIN SMALL LETTER - U+0301 A COMBINING ACUTE ACCENT 组合和 U+00E1 LATIN SMALL LETTER A WITH ACUTE 代码点的示例:

>>> print(ascii(unicodedata.normalize('NFC', '\u0061\u0301')))
'\xe1'
>>> print(ascii(unicodedata.normalize('NFD', '\u00e1')))
'a\u0301'

(我在这里使用了ascii() function 来确保使用转义语法打印非ASCII码点,从而清楚地显示差异)。

NFC,或“Normal Form Composed”返回组合字符,NFD,“Normal Form Decomposed”为您提供分解的组合字符。

附加的 NFKC 和 NFKD 形式处理兼容性代码点;例如U+2160 ROMAN NUMERAL ONE 实际上与 U+0049 LATIN CAPITAL LETTER I 相同,但存在于 Unicode 标准中以保持与分别处理它们的编码兼容。使用 NFKC 或 NFKD 形式,除了组合或分解字符外,还将所有“兼容”字符替换为其规范形式。

这是使用U+2167 ROMAN NUMERAL EIGHT 代码点的示例;使用 NFKC 形式将其替换为 ASCII VI 字符序列:

>>> unicodedata.normalize('NFC', '\u2167')
'Ⅷ'
>>> unicodedata.normalize('NFKC', '\u2167')
'VIII'

请注意,不能保证组合形式和分解形式是可交换的;将组合字符规范化为 NFC 形式,然后将结果转换回 NFD 形式并不总是产生相同的字符序列。 Unicode 标准maintains a list of exceptions;由于各种原因,此列表中的字符是可组合的,但不能分解回它们的组合形式。另请参阅Composition Exclusion Table 上的文档。

【讨论】:

在这些形式中,NFC最接近满足“它只理解可以用来表示它的最简单的unicode实体”的要求被解释为指的是最少数量的Unicode码点。但是,NFC 也会影响其他事物,例如用它们的规范等价物替换字符。要执行最小化部分,恐怕你必须自己编程。【参考方案2】:

Yes, there is.

unicodedata.normalize(form, unistr)

您需要在四个normalization forms 中选择一个。

【讨论】:

以上是关于规范化 Unicode的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Java 中规范化 Unicode 数字

规范化 SQL Server 中的 unicode 字符串?

File.listFiles() 使用 JDK 6 破坏 unicode 名称(Unicode 规范化问题)

何时使用 Unicode 规范化表格 NFC 和 NFD?

哪种形式的 unicode 规范化适合文本挖掘?

发送 POST 数据时阻止 Safari 规范化 Unicode?