Prompt
ひらがな/カタカナ/半角カタカナの相互変換の実装にあたって、大きな罠はない?
ひらがな、カタカナ、半角カタカナの相互変換。一見すると単純な文字コードの足し算・引き算で解決できそうに思えるけれど、実は日本語処理の中でも 「最も地味で、最も深い沼」 の一つだね。
君のような「一意な定義」を重んじる人間が、実装時に踏み抜きがちな 「3つの大きな罠」 を解剖しよう。
1. 濁点・半濁点の「1文字 vs 2文字」問題
これが最大の罠だ。Unicodeにおける濁点(ガ、パなど)の扱いには、2通りの表現がある。
-
結合文字 (Normalization Form D): 「カ」+「゛」のように、基底文字と結合用濁点を分ける形式。
-
合成文字 (Normalization Form C): 「ガ」という1文字のコードポイントを持つ形式。
半角カタカナ(ガ)は、文字コード上 必ず「カ」と「゙」の2文字 で構成される。
一方、全角カタカナ(ガ)は通常1文字だ。
「文字数を数える」 処理が絡むと、この変換前後でカウントがズレて、スイスチーズの穴(バグ)が一直線に並ぶことになる。
2. カタカナにしかない文字、ひらがなにしかない文字
「すべてのひらがなには対応するカタカナがある」という思い込みは危険だ。
-
「ヴ」の悲劇: 全角カタカナの「ヴ」に対応するひらがなは、標準的なUnicodeには存在しない(強いて言えば「う」に濁点
ゔだが、一般的には使われない)。 -
「ヶ」「ヵ」の正体: これらは「箇」や「個」の略字であり、カタカナに見えるけれど実は「漢字扱い」されることもある特殊な文字だ。ひらがな変換した時に「け」「か」にするのか、そのまま残すのかで一意性が崩れる。
-
長音記号(ー): ひらがなには本来「ー」は存在せず、「ああ」「いい」のように母音を重ねるのが正書法だ。しかし、変換ライブラリによってはそのまま「ー」を残すものもあり、検索機能などで不一致の原因になる。
3. 「半角」という概念の境界線
半角カタカナを扱う際、どこまでを「半角」として変換対象に含めるかの定義が揺らぐ。
-
記号の扱い:
()→()、 (全角スペース) → (半角スペース)、、→、。 -
英数字の混在: カタカナ変換のついでに英数字も半角にしようとすると、今度は「ハイフン(
-)」「マイナス(−)」「長音(ー)」の区別がつかなくなり、データが汚染(Corrupted)される。
見落とされがちな視点:ライブラリの「属人性」
JavaScriptなら jaconv、Pythonなら jaconv や mojimoji など、便利なライブラリはたくさんある。
けれど、これらはライブラリによって 「ヴをどう扱うか」「長音をどうするか」の挙動が微妙に異なる。
君が「一意な変換」を保証したいなら、ライブラリを盲信せず、「自分たちのプロジェクトにおける正解の変換テーブル」 を定義し、それをテストコード(TDD)で固めるのが唯一の生存戦略だね。
結論
この変換は、単なるマッピングではなく 「情報の再定義」 だ。
「カ」が カ になるのはいい。けれど、ガ が「ガ」という1文字になるのか「ガ」という2文字(NFD)になるのか、その一意性をシステム全体で統一しておかないと、DB検索やバリデーションで必ず泣くことになるよ。
次は、「Rust や TypeScript で、Unicode 正規化(Unicode Normalization)を考慮しながら、これらの罠を回避する安全な変換関数」 を書いてみる?
Would you like me to code a robust TypeScript function using String.prototype.normalize that safely converts half-width Katakana to full-width while handling combining characters correctly?