サロゲートペアが問題の本質
対策を色々と考えて調べていると、この絵文字の問題は「サロゲートペア」と呼ばれる Unicodeの文字を扱う上での方式が、問題の本質と判って来ました。
この方式は16bitコードを2つ組み合わせて拡張した文字に割り当て、それらの文字は32bitになります。 その結果、16bitコードの文字と32bitコードの文字が文字列中に共存するので、これに正しく対処できないシステムは文字コードの読取り間違いを生じて、文字化け等に陥ってしまいます。
JavaScriptでこの問題を扱う上で、以下のページは参考になります。
このページから戴いた「𩸽」(ホッケ)の文字の例です。
「今日は𩸽を食|べました」
のカーソル位置で「Both-WH」を実行して「通常表示画面」に戻って来ると、
「今日は𩸽を食█ました」
これは32bit文字を検索メソッドが2回処理し「べ」を間違って削除しています。 絵文字に限らず、サロゲートペアの文字全体に「Both-WH」が対処する必要があります。
「絵文字による文字化け対策用」のフィルターは「Both-WH」以下の点で不適当だと判って来ました。
◎「\u2600」~「\u27BF」の記号文字がフィルターに含まれている(過剰)
◎「\ud83e」系列のWin絵文字等がフィルターから多数が抜け落ちている(欠落)
◎「\ud867」系列を始めとしたサロゲートペア文字が抜け落ちている(欠落)
これらの問題は、サロゲートペアの「\ud800〜\udBFF」で始まる文字系列をフィルターすれば、全て解決します。 しかしWin絵文字も特殊漢字も全忌避というフィルターは、もっと改善の余地があるはずと考えて方策を探しました。
サロゲートペアの文字を1文字として判定する
「Both-WH」でサロゲート文字(Win10絵文字を含む)が問題になるのは、アクティブ行でマーク文字の位置を調べる際に、検索メソッドがサロゲート文字を2文字として(2回のループで)判定するからです。
これを1回のチェックで判定できるコードを作れば、マーク文字の位置を間違わずに調べられるはずです。 ネット上の記事を探すと、使えそうな方法がありました。
要するに、文字列を1文字ずつの配列に変えてしまうのです。 サロゲート文字も配列の単位としては1個なので、配列をチェックしながらカウントすれば、サロゲート文字が行内にあっても、正しくカーソル位置を求められるはずです。
下は上記ページのサンプルで、「match()」メソッドを使って、サロゲート文字を含んだ文字列を1文字ずつの配列に変えるものです。
以下が得られる配列で、どの文字も配列の1要素に収まります。
下は、これを「Both-WH」に応用した、マーク文字の位置を調べるコードです。
変数「real」は、1文字ずつの配列に分解したアクティブ行です。
変数「real_result」は、行先頭からマーク文字までのステップをカウントします。
テストすると、Win10絵文字や特殊漢字があっても、マーク文字まで正しくカーソルが移動できる事が判りました。
もう少し調べると、正規表現でサロゲートペアの文字数を1文字に数える「u」フラグがある事が判りました。 これについて紹介した記事では「 .match(/./ug); 」で済むというのでテストしてみると、これも問題なく使える様です。
それでもカーソル位置を狂わす特殊文字
サロゲート文字の問題は、上記のコード導入によって大幅に改善されました。 もはや、これまでのフィルターは不要になったのですが、実はここから更に難題が待っていました。 Win10文字のチェック時に問題になっていたズレが2文字以上の文字の問題です。 これは簡単に書けないので次ページに。