この記事には古い内容が含まれています。以下で挙げている issue は、 mojimoji 最新版である v0.0.13 で解決されています(2024/01/13 追記)。
はじめに
- mojimoji とは
- Habachen とは
mojimoji と Habachen は、いずれもネイティブ拡張を用いた CPython 上で動作する日本語の全角/半角変換ライブラリです。 Habachen は私が開発しています。
以前書いた Habachen の紹介記事ではそのパフォーマンスに焦点を当てていますが、元々は mojimoji の不満点を解消した CPython 用の日本語文字列変換ライブラリを自前で作り上げることが目的で1、高速化は二の次でした。
Habachen では、全角/半角に加えひらがな/カタカナの相互変換も可能になっている他、 mojimoji に見られたいくつかの問題点も解消されています。
Issues
2023年10月現在、mojimoji では以下の issue が立てられています。
2024年1月現在、更新に伴い close 済みです(2024/01/13 追記)。
バックスラッシュが変換されない
タイトルの通りです。
- Habachen の場合
期待通り、半角バックスラッシュ (U+005C) と全角バックスラッシュ (U+FF3C) が相互に変換されます2。
>>> import habachen
>>> habachen.han_to_zen('\\')
'\'
>>> habachen.zen_to_han('\')
'\\'
めっちゃ環境依存なバグ
上のリンクで貼られていたコードでは再現できなかったのですが、以下のコードを Google Colab 上で実行してみたところ、おそらく報告されているものと同じ不具合により、セッションがクラッシュしました。
!pip install mojimoji
import mojimoji
def bug_test(text):
text = mojimoji.zen_to_han(text)
text = mojimoji.han_to_zen(text)
return text
bug_test("゙ンライフレキ")
どうやら文字列全体が半角の濁点から始まる場合に han_to_zen()
関数内で未定義動作を踏んでしまっているようです。今回の試行でのクラッシュは、未初期化変数の参照3とメモリブロックの範囲外アクセスが連鎖して malloc ヘッダが破壊されたことにより発生したものと見られます。
- Habachen の場合
以下のコードは、 Google Colab 上で正常に動作します。
!pip install habachen
import habachen
def bug_test(text):
text = habachen.zen_to_han(text)
text = habachen.han_to_zen(text)
return text
bug_test("゙ンライフレキ")
Cannot install on Python 3.12
本文で書かれている通り、 Cython によって生成される C++ コード内で古い API が使われているために Python 3.12 でインストールできないという問題です。 mojimoji では Python 3.3 以降非推奨である文字列表現形式 (Py_UNICODE*) がバッファとして利用されており、これと紐づけられている関数群が Python 3.12 で軒並み廃止されたことが影響しています。
なお、この issue に対しては現在プルリクエストが出されています。
- Habachen の場合
Python 3.12 でもインストールできます。
リンク追加要請の issue もありましたが、ここでは割愛します。
最後に
mojimoji はシンプルで扱いやすいライブラリですが、現在バージョン 0.0.12 ではいくつか基本的な部分での問題が確認されています4。 Habachen では、ここで取り上げた問題は解消されており、パフォーマンスも改善されているので、高速な全角/半角・ひらがな/カタカナ変換ライブラリを求めている方は、一度 Habachen を試していただければと思います。
本記事では CPython のネイティブ拡張を扱いましたが(C/C++ 難しい…)、最後にオススメの Pure Python 文字列変換ライブラリのリンクを貼っておきます。 Pure Python 実装ライブラリの利点としては、 C コンパイラが利用できない環境でもインストールできること、 Python 本体のバージョンアップによる内部 API 変更の影響を受けにくいことが挙げられます。
- jaconv
- Utsuho
-
全角/半角変換自体はそれほど複雑な処理ではないのですが、それなりに速いものを CPython 拡張モジュールとしてバグなく実装するのは結構面倒くさかったりします。 ↩
-
環境によっては、半角バックスラッシュが半角の円マークとして表示されるかもしれませんが、コードポイント上は同じものを指しています。 ↩
-
この時点で未定義動作となります。未定義動作なので、環境や条件によっては別の不具合が生じたり、問題が表出しなかったりしても不思議ではありません。 ↩
-
作者の方は他のことで忙しいのか、issue #21 が立てられてから1年以上更新されて
いないようですいなかったのですが、先日アップグレードされたようです(2024/01/13 追記)。 ↩