web-dev-qa-db-ja.com

Unicodeの正規化

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

もちろん、すべての文字を反復処理したり、手動で置換したりすることもできますが、それは効率的ではなく、特殊なケースの半分を逃して間違いを犯すと確信しています。

55
michaelmeyer

unicodedataモジュールは .normalize() function を提供します。NFC形式に正規化します:

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

NFC、または「Normal Form Composed」は合成文字を返し、NFD、「Normal Form Decomposed」は分解され、結合された文字を返します。

追加のNFKCおよびNFKDフォームは、互換性のあるコードポイントを扱います。例えばU + 2160(ROMAN NUMERAL ONE)は実際にはU + 0049(LATIN CAPITAL LETTER I)と同じものですが、Unicode標準に存在し、それらを個別に処理するエンコーディングとの互換性を維持しています。文字の構成または分解に加えて、NFKCまたはNFKDのいずれかの形式を使用すると、すべての「互換性」文字が標準形式に置き換えられます。

>>> unicodedata.normalize('NFC', u'\u2167')  # roman numeral VIII
u'\u2167'
>>> unicodedata.normalize('NFKC', u'\u2167') # roman numeral VIII
u'VIII'

合成および分解された形式が通信可能であるという保証はないことに注意してください。結合された文字をNFC形式に正規化してから、結果をNFD形式に戻すと、常に同じ文字シーケンスが得られるとは限りません。Unicode標準 例外のリストを維持 ;このリストの文字は構成可能ですが、さまざまな理由により、組み合わせた形式に分解することはできません。 構成除外テーブル のドキュメントも参照してください。

81
Martijn Pieters

はい、あります

unicodedata.normalize(form, unistr)

4つの 正規化形式 のいずれかを選択する必要があります。

7
SLaks