DEVGRU

プログラミングと競馬予想について書きます

neologdn が使えない (Python 3.8では)ので unicodedata.normalize() を使ったが、やっぱり使えた話

データの名寄せに必要な正規化で同僚から neologdn を進められて使おうとしたが、 Python 3.8 に対応していなくて、 unicodedata.normalize() で事足りたけど、3日前に対応していたお話です。

広告

ユーザの入力値とデータベースを照合して最もマッチする値を取得する実装が必要になり、同僚が neologdn ( PyPI) を教えてくれたので、さっそうと pip install neologdn したところ、見事に使えなかった。

$ pip install neologdn
...(なにか大量のコンパイルエラー)

検索して出てくる記事や、 PyPIの配布物 を見たところ、Python 3.7 までのビルド済みパッケージしかなく、 Python 3.8 でビルドが走るがエラーになる、といった具合のようだった。

ユーザの入力値はせいぜいカタカナひらがな数字の半角全角程度の変換だったので、unicodedata.normalize() で済ませた。

>>> unicodedata.normalize("NFKC", "あいうえお")
'あいうえお'
>>> unicodedata.normalize("NFKC", "アイウエオ")
'アイウエオ'
>>> unicodedata.normalize("NFKC", "12345.6")
'12345.6'
>>> unicodedata.normalize("NFKC", "㈱㈲")
'(株)(有)'

あとはレーベンシュタイン距離でデータベースに入っている値との類似度で並べ替えることで、無事タスクを完了することができた。

from unicodedata import normalize
from Levenshtein import distance

onigiri_db = ["ウメボシ", "タラコ", "オカカ"]


def lookup_onigiri(input_):
    with_similarities = [
        (
            onigiri,
            distance(onigiri, normalize("NFKC", input_))
            / max(len(onigiri), len(input_)),
        )
        for onigiri in onigiri_db
    ]

    for onigiri, similarity in sorted(with_similarities, key=lambda elem: elem[1]):
        print(f"{onigiri}\t{similarity:.4}")


if __name__ == "__main__":
    import sys

    if len(sys.argv) >= 2:
        lookup_onigiri(sys.argv[1])
    else:
        print(
            f"""
Usage:
    {sys.argv[0]} おにぎりの具
""".lstrip()
        )
$ python similarity.py ウメ
ウメボシ    0.5
タラコ   1.0
オカカ   1.0

そしてこの記事に顛末を書いている最中、 pip install neologdn のコンパイルエラーをもう一度拝もうとしたところ、インストールが無事終了してしまった。

pip install neologdn
Collecting neologdn
  Using cached https://files.pythonhosted.org/packages/12/46/0bb6c64ff8b9c549a3fbdff68240155fb5f938a2563ce5396278973919f0/neologdn-0.5.1.tar.gz
Installing collected packages: neologdn
  Running setup.py install for neologdn ... done
Successfully installed neologdn-0.5.1

はて…? と思って PyPI を見たところ、なんと3日前に更新されていたようだ。しかも2年と少しぶりに。

PyPI のスクリーンショット
https://pypi.org/project/neologdn/#history のスクリーンショット(2021/05/05)

GitHub のスクリーンショット (2021/05/05)
GitHub のスクリーンショット (2021/05/05)

タスクが 2021/05/02 の日中で、PyPIの更新日時が "2021-05-02 20:44:14" 1 なので、半日ほどのすれ違いだったようだ。なんと…。

自身のタスクには間に合わなかったが、同僚が別のタスクで使用する予定だったので非常にタイミングが良かった。

Pythonで動かして学ぶ 自然言語処理入門

Pythonで動かして学ぶ 自然言語処理入門

現場で使える!Python自然言語処理入門

現場で使える!Python自然言語処理入門


  1. スクリーンショットで示した PyPI の日付にマウスオーバーすると表示される