[Python] ‘ピ’ と ‘ピ’ は違う文字?unicode正規化をやってみる

MacOS を利用してPythonプログラムを書いている時に発生した問題。文字列一致判定のプログラムを書いても判定結果がどうしてもTrueにならず、頭を悩ませたことがあったため今後のために記載。

目次

発生していた問題

ざっくり以下のようなイメージの判定処理を書いたが、どうしてもTrue判定にならない。

# str1 : globでファイル名検索をした結果として、"ピアノ.png"の文字列を保持
str2 = "ピアノ.png"

if str1 == str2:
 return True
else:
 return False

原因は文字コードの差異

プロンプトで見ても全く同じ文字に見えるが、文字列をencodeしてみると確かに一致しない。
原因を調べていると、文字コードの差異により、見た目が一緒に見えてもpythonでの判定で不一致になっていることがわかった。

最近のMacOSの文字コードは utf-8のようですが、以前は utf-8-mac という文字コードだったよう。
この utf-8-mac は utf-8 と文字の見た目は同じだが、違いとしては utf-8-mac は濁点・半濁点を1文字としてカウントしている点が、utf-8と異なる。

テキストエディタに貼り付け、backspaceキーで1文字ずつ削除すると、utf-8-macの文字は濁点・半濁点だけを削除することができます※MACで独自のコードがあるなんて知らなかった。。。

解決方法

今回の文字コード差異を解決するためにはUnicode正規化を行います。Pythonでは、主に以下の4つの正規化形式が用いられます。(utf-8 は NFC 、utf-8-mac は NFD に該当)

  • NFC (Normalization Form C): 既存の結合文字列を1つの合成文字に置き換えます。
  • NFD (Normalization Form D): 合成文字を分解し、結合文字列で表現します。
  • NFKC (Normalization Form KC): NFCに加え、互換性のある文字を変換します。
  • NFKD (Normalization Form KD): NFDに加え、互換性のある文字を変換します。

Pythonでは、unicodedataモジュールを使用して、Unicode正規化を行うことができます。

import unicodedata # <- モジュールを追加

# str1 : globでファイル名検索をした結果として、"ピアノ.png"の文字列を保持
str2 = "ピアノ.png"

normalized_str2 = unicodedata.normalize('NFC', str2) # NFCに正規化

if str1 == normalized_str2:
 return True
else:
 return False

これで文字列一致判定で True が返ってくるようになります。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次