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 が返ってくるようになります。