【Angular Utilities】NFD 文字を NFC に変換する Normalize To NFC を作った
主に MacOS の Finder なんかで問題になる、NFD 文字。濁点と半濁点が別の文字に別れており、Finder からファイル名をコピペしたりすると、「バイブス」という文字列が「ハ゛イフ゛ス」のようになってしまう、というものだ (この例は全角の濁点文字で再現)。こうなると、この文字列は「バイブス」と検索してもヒットしなくなってしまう。
ついでに、Windows などで通常どおり濁点・半濁点付きの文字になるのは NFC と呼ばれる。
ちょこちょこ MacOS でファイル名などをコピペすることがあるので、この NFD 濁点・NFD 半濁点を検知して、通常の濁点・半濁点付きの文字に置換するツールを作った。
問題になるのは、日本語においては濁点と半濁点が付く文字のみ。「ガバザダバパ」行と、「ヴ」だけである。そこで、ひらがなとカタカナでこれらの文字を表す文字コードを配列で持っておき、辞書的に利用することにした。
/** 清音文字の辞書 : 濁音文字の配置と揃えることで、同じ index 値で参照できるようにしておく */
const uncombinedKanaDict = [
0x304B, 0x304D, 0x304F, 0x3051, 0x3053, // かきくけこ
0x3055, 0x3057, 0x3059, 0x305B, 0x305D, // さしすせそ
0x305F, 0x3061, 0x3064, 0x3066, 0x3068, // たちつてと
0x306F, 0x3072, 0x3075, 0x3078, 0x307B, // はひふへほ (ば行用)
0x306F, 0x3072, 0x3075, 0x3078, 0x307B, // はひふへほ (ぱ行用)
0x3046, // う
0x30AB, 0x30AD, 0x30AF, 0x30B1, 0x30B3, // カキクケコ
0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD, // サシスセソ
0x30BF, 0x30C1, 0x30C4, 0x30C6, 0x30C8, // タチツテト
0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, // ハヒフヘホ (バ行用)
0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, // ハヒフヘホ (パ行用)
0x30A6 // ウ
];
/** 濁音文字の辞書 : 清音文字の配置と揃えることで、同じ index 値で参照できるようにしておく */
const combinedKanaDict = [
0x304C, 0x304E, 0x3050, 0x3052, 0x3054, // がぎぐげご
0x3056, 0x3058, 0x305A, 0x305C, 0x305E, // ざじずぜぞ
0x3060, 0x3062, 0x3065, 0x3067, 0x3069, // だぢづでど
0x3070, 0x3073, 0x3076, 0x3079, 0x307C, // ばびぶべぼ
0x3071, 0x3074, 0x3077, 0x307A, 0x307D, // ぱぴぷぺぽ
0x3094, // ゔ
0x30AC, 0x30AE, 0x30B0, 0x30B2, 0x30B4, // ガギグゲゴ
0x30B6, 0x30B8, 0x30BA, 0x30BC, 0x30BE, // ザジズゼゾ
0x30C0, 0x30C2, 0x30C5, 0x30C7, 0x30C9, // ダヂヅデド
0x30D0, 0x30D3, 0x30D6, 0x30D9, 0x30DC, // バビブベボ
0x30D1, 0x30D4, 0x30D7, 0x30DA, 0x30DD, // パピプペポ
0x30F4 // ヴ
];
NFD 文字になっている場合、たとえば「ザ」は「サ゛」という2文字になっている。入力文字列を1文字ずつ切り取って検証していく中で、
- 次の文字が NFD 濁点 (
゙
) か NFD 半濁点 (゚
) の場合
かつ、
- 現在検証中の文字が変数
uncombinedKanaDict
の中にある場合
に、uncombinedKanaDict
のどこにこの文字があるか、findIndex()
で添字を取得しておく。
変数 combinedKanaDict
とは、清音と濁音の文字を配列の順番で対応付けてあるので、「サ」が uncombinedKanaDict[31]
にあることが分かれば、「ザ」は combinedKanaDict[31]
にあることが分かる。
このようにして、「清音文字 + NFD 濁点」の組み合わせから、通常の濁音文字を取得して結合しているのである。
ところで、NFD 用の濁点 (゙
) と半濁点 (゚
) は、通常の全角濁音 (゛
・゜
) および半角濁音 (゙
・゚
) とは別の文字で、手前の文字と合成して使うことを前提として構成されている。そのため、通常 Mac で文字列選択する際も、濁点だけ・半濁点だけを選択することができず、手前の文字が濁音のない文字であっても、変な形で強制的に合成表示されてしまう。
あまりないとは思うが、何かの拍子に「オ゜」のようにありえない濁音ができてしまった時に、単独の NFD 濁音文字を全角の濁音文字に変換するオプションも用意した。これなら、単独の濁音文字が混じっていてもコピペしたり扱いやすくなる。
ついでに、ngx-clipboard というモジュールを導入して、変換後の文字列をコピペしやすくした。
内部的には、よくある実装のとおり、textarea
要素を画面外に生成して、文字列をコピーしている。自分で実装するとなるとちょいと面倒になるので、こういう風にエコな使い回しができるのは良き良き。