「1日1python」の時間です(ただし隔週放送)。

みろりhpの記事をpythonで読み込んでいたら、スゲーイヤな問題に咬まれたのでそれについて書く。

マジびっくりなことに、 は違う文字だ。前者は「波ダッシュ(WAVE DASH)」といって、後者が「全角チルダ(FULLWIDTH TILDE)」という。 pythonで下記スクリプトを実行してみればそれがわかる。

wavedash = '〜'        # 前者。波ダッシュ。
fullwidthtilde = '~'  # 後者。全角チルダ。
print(wavedash == fullwidthtilde)  # Falseになりやがる。ビックリだな。

UTF-8にはどっちの文字も含まれてるんだが、EUC-JPとかSJISには全角チルダのほうが含まれていないらしい。

見分け方はこう。

# b'\xe3\x80\x9c' って出れば波ダッシュ。
print(str(wavedash.encode('utf8')))

# b'\xef\xbd\x9e' って出れば全角チルダ。
print(str(fullwidthtilde.encode('utf8')))

上の見分け方を使って判別関数を作っといたぜ。

def is_WAVEDASH(char):
    return char.encode('utf8') == b'\xe3\x80\x9c'

print(is_WAVEDASH(wavedash))        # Trueになる。
print(is_WAVEDASH(fullwidthtilde))  # Falseになる。


def is_FULLWIDTHTILDE(char):
    return char.encode('utf8') == b'\xef\xbd\x9e'

print(is_FULLWIDTHTILDE(wavedash))        # Falseになる。
print(is_FULLWIDTHTILDE(fullwidthtilde))  # Trueになる。

変換する関数も作ったぜ。てか今回の問題で俺がいちばん必要としたのがこれ。波ダッシュと全角チルダが混在するデータで処理をしようとするとどっかでオカシクなる。文字化けしたり、見た目には同じ文字なのに「違う」って言われたり(冒頭のヤツ)ね。そういう恐れのある文字列は全部以下の関数を通しちまおうぜ。

# 波ダッシュを全角チルダに変換する。reverseにTrue渡せば逆になるよ。
def convert_WAVEDASH_to_FULLWIDTHTILDE(string, reverse=False):
    wavedash = (b'\xe3\x80\x9c').decode('utf-8')
    fullwidthtilde = (b'\xef\xbd\x9e').decode('utf-8')
    if not reverse:
        return string.replace(wavedash, fullwidthtilde)
    else:
        return string.replace(fullwidthtilde, wavedash)

この問題に出会ったのは、みろりhpのデータをxmlエクスポートしたときだ。ナゼかこのブログ([2019-05-25 追記] 当時の jugem ブログ)はEUC-JP(波ダッシュしかないほう)で書かれているのに、出力するとUTF-8(どっちもあるほう)になり、しかももともと含まれていた波ダッシュがすべて全角チルダに置き換わる謎仕様だったんだ。それを処理しようとしたらおかしなことになった。そこでこの調査が必要になったわけ。