Pythonで文字列をUnicode正規化:unicodedata.normalizeで比較問題を解決


Unicode正規化とは?

 

Unicodeには、同じ文字でも複数の表現方法が存在する場合があります。例えば、「ガ」という文字は、一つの文字「ガ (U+30AC)」として表現されることもあれば、「カ (U+30AB)」と「゛ (U+3099)」のように、基本となる文字と結合文字の組み合わせで表現されることもあります。

このような複数の表現方法が存在すると、文字列の比較や検索が正しく行えない問題が発生します。Unicode正規化とは、これらの異なる表現を統一された一つの形式に変換することで、このような問題を解決するプロセスです。


 

unicodedata.normalize() の基本

 

Pythonの標準ライブラリである unicodedata モジュールは、Unicodeデータベースへのアクセスと、文字列の正規化機能を提供します。特に、unicodedata.normalize() 関数は、文字列を特定の正規化形式に変換するために使用されます。

 

書式

 

Python
 
unicodedata.normalize(form, unistr)
  • form: 正規化形式を指定する文字列。

  • unistr: 正規化したいUnicode文字列。

 

正規化形式の種類

 

主な正規化形式は以下の4種類です。

  • ‘NFC’ (Normalization Form C): 結合文字を可能な限り合成して、最も短い形式にします。最も一般的に使用されます。

  • ‘NFD’ (Normalization Form D): 結合文字を可能な限り分解して、合成前の形式に戻します。

  • ‘NFKC’ (Normalization Form KC): ‘NFC’ と同様に合成しますが、互換性文字(例: 全角数字や半角カナ)も正規化します。

  • ‘NFKD’ (Normalization Form KD): ‘NFD’ と同様に分解しますが、互換性文字も正規化します。


 

正規化の具体例

 

 

合成と分解の例:NFCとNFD

 

「ガ」という文字を使って、NFCとNFDの違いを見てみましょう。

Python
 
import unicodedata

# ガ (U+30AC) - 合成済み
char_ga_composed = 'ガ'

# カ (U+30AB) + ゛ (U+3099) - 分解済み
char_ka_dakuten_decomposed = 'ガ' # 'カ' + '゛'

print(f"オリジナル1: {char_ga_composed}, 長さ: {len(char_ga_composed)}")
print(f"オリジナル2: {char_ka_dakuten_decomposed}, 長さ: {len(char_ka_dakuten_decomposed)}")

# NFC (合成)
normalized_nfc1 = unicodedata.normalize('NFC', char_ga_composed)
normalized_nfc2 = unicodedata.normalize('NFC', char_ka_dakuten_decomposed)
print(f"NFC1: {normalized_nfc1}, 長さ: {len(normalized_nfc1)}")
print(f"NFC2: {normalized_nfc2}, 長さ: {len(normalized_nfc2)}")
print(f"NFCで比較: {normalized_nfc1 == normalized_nfc2}") # True

# NFD (分解)
normalized_nfd1 = unicodedata.normalize('NFD', char_ga_composed)
normalized_nfd2 = unicodedata.normalize('NFD', char_ka_dakuten_decomposed)
print(f"NFD1: {normalized_nfd1}, 長さ: {len(normalized_nfd1)}")
print(f"NFD2: {normalized_nfd2}, 長さ: {len(normalized_nfd2)}")
print(f"NFDで比較: {normalized_nfd1 == normalized_nfd2}") # True

この例では、異なる表現の「ガ」がNFCとNFDによって同じ内部表現に変換され、比較が正しく行えるようになることがわかります。

 

互換性文字の正規化:NFKCとNFKD

 

NFKCやNFKDは、見た目は同じだがUnicode上では異なる互換性文字を正規化する際に役立ちます。

Python
 
# 全角数字と半角数字の例
full_width_num = '123'
half_width_num = '123'

# NFKC (互換性文字を正規化して合成)
normalized_nfkc_full = unicodedata.normalize('NFKC', full_width_num)
normalized_nfkc_half = unicodedata.normalize('NFKC', half_width_num)
print(f"NFKC (全角): {normalized_nfkc_full}") # '123' に変換される
print(f"NFKC (半角): {normalized_nfkc_half}")
print(f"NFKCで比較: {normalized_nfkc_full == normalized_nfkc_half}") # True

# 半角カタカナと全角カタカナの例
half_width_kana = 'カタカナ'
full_width_kana = 'カタカナ'

normalized_nfkc_half_kana = unicodedata.normalize('NFKC', half_width_kana)
normalized_nfkc_full_kana = unicodedata.normalize('NFKC', full_width_kana)
print(f"NFKC (半角カナ): {normalized_nfkc_half_kana}") # 'カタカナ' に変換される
print(f"NFKC (全角カナ): {normalized_nfkc_full_kana}")
print(f"NFKCで比較: {normalized_nfkc_half_kana == normalized_nfkc_full_kana}") # True

NFKCを使用すると、全角数字が半角数字に、半角カタカナが全角カタカナに変換され、異なる入力形式でも比較が可能になります。

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<月1開催>放送作家による映像ディレクター養成講座

<オンライン無料>ゼロから始めるPython爆速講座