规范化 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 V
和 I
字符序列:
>>> 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的主要内容,如果未能解决你的问题,请参考以下文章
规范化 SQL Server 中的 unicode 字符串?