📝

全角英数字を半角に変換

2021/07/01に公開1

全角英数字を半角に変換したい時、javascriptでは以下のようにします。

str.replace(/[---]/g, function (s) {
  return String.fromCharCode(s.charCodeAt(0) - 0xfee0);
});

pythonで同じことをする方法を探していたらUnicode正規化という言葉を見付けました。

例えばzennではtopicsを指定することができます。ユーザーによってはpython(半角)python(全角)と書く人がいるかもしれません。そうなるとpython(半角)python(全角)は別のtopicsになってしまいます。

このような重複をなくすためにUnicode正規化すると、ユーザーが入力したpython(全角)python(半角)に修正されます。

そしてpythonの標準ライブラリであるunicodedataを使うと簡単に正規化することができます。

import unicodedata


s = "123①②③,㍻㍉㌦㎡㈱№,abcABC,Å🅱©,123abcABC,<>,アイウエオカキクケコ"
unicodedata.normalize("NFKC", s)

# '123123,平成ミリドルm2(株)No,abcABC,Å🅱©,123abcABC,<>,アイウエオカキクケコ'
変換前 変換後 備考
123①②③, 123123 全角数字と機種依存文字
㍻㍉㌦㎡㈱№ 平成ミリドルm2(株)No 機種依存文字
abcABC abcABC 全角英字
Å🅱© Å🅱© 英字の記号
123abcABC 123abcABC 半角英数字(変わらず)
<> <> 記号
アイウエオカキクケコ アイウエオカキクケコ カタカナ

全角英数字だけでなく、機種依存文字や括弧、半角カタカナも変換されています。

normalize関数の引数に指定したNFKCは正規化の形式で、以下4つから選べます。

s = "123①②③,㍻㍉㌦㎡㈱№,abcABC,Å🅱©,123abcABC,<>,アイウエオカキクケコ"
[
    unicodedata.normalize("NFC", s),
    unicodedata.normalize("NFKC", s),
    unicodedata.normalize("NFD", s),
    unicodedata.normalize("NFKD", s),
]
['123①②③,㍻㍉㌦㎡㈱№,abcABC,Å🅱©,123abcABC,<>,アイウエオカキクケコ',
 '123123,平成ミリドルm2(株)No,abcABC,Å🅱©,123abcABC,<>,アイウエオカキクケコ',
 '123①②③,㍻㍉㌦㎡㈱№,abcABC,Å🅱©,123abcABC,<>,アイウエオカキクケコ',
 '123123,平成ミリドルm2(株)No,abcABC,Å🅱©,123abcABC,<>,アイウエオカキクケコ']

参考サイト

unicodedata --- Unicode データベース

Unicode正規化 - Wikiwand

Unicode正規化

正規化形式別のユニコード正規化の振る舞いの違いを見てみる | 分析ノート

GitHubで編集を提案

Discussion

bilzardbilzard

C形式とD形式は見た目からは違いが分からないようです。
以下のコードスニペットのようにバイナリで表現すると判別出来ました。
(C形式はアクセント文字を1つの文字として保持しているのに対し、D形式は元の文字とアクセントの2文字として保持しているようです)

import pandas as pd
import unicodedata as ud

df = pd.DataFrame({"text": ["é"]})
df["text"] = df["text"].apply(lambda x: ud.normalize("NFKD", x))
df["text"].apply(lambda x: x.encode()).head(1).item()
  • NFKD -> b'e\xcc\x81'
  • NFKC -> b'\xc3\xa9'