规范化Unicode

102

在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']

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

2个回答

140

unicodedata模块提供了一个.normalize()函数,您想要将其规范化为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()函数,以确保使用转义语法打印非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标准维护了一个异常列表;此列表中的字符是可组合的,但由于各种原因无法分解回其组合形式。还请参阅有关组合排除表的文档。

1
在这些形式中,NFC 最接近满足“它仅包含可用于表示其的最简Unicode实体”的要求,被解释为指最少数量的Unicode代码点。然而,NFC 也会影响其他方面,例如通过它们的规范等效物替换字符。要仅执行缩小部分,恐怕您必须自己编程。 - Jukka K. Korpela

10

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