1. ホーム
  2. python

[解決済み] ユニコードの正規化

2023-06-10 16:13:42

質問

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

もちろん、すべての文字を繰り返し処理し、手動で置換などを行うこともできますが、効率的ではありませんし、特殊なケースの半分を見逃し、間違いを犯すことは間違いないでしょう。

どのように解決するのですか?

この 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 形式に変換し直しても、同じ文字列になるとは限らないので、結合形式と分解形式が可換であるという保証はないことに注意しましょう。ユニコード規格の は例外のリストを保持しています。 このリストにある文字は、様々な理由により、合成可能ですが、合成された形に分解して戻せません。のドキュメントも参照してください。 合成除外表 .