結合文字
直前の基底文字に結合して表示される Unicode 文字。ダイアクリティカルマークや濁点などが該当する。
結合文字 (Combining Character) とは、単独では表示されず、直前の基底文字に結合して一つの文字として表示される Unicode 文字です。結合用ダイアクリティカルマーク (U+0300 から U+036F) が代表的で、アクセント記号、ウムラウト、セディーユなどが含まれます。
たとえば、ラテン文字「a」(U+0061) に結合用アキュートアクセント (U+0301) を続けると「á」として表示されます。日本語では、結合用濁点 (U+3099) や結合用半濁点 (U+309A) が該当し、「か」+ U+3099 で「が」を表現できます。タイ語やアラビア語など、結合文字を多用する言語も多く、Unicode の結合文字は 800 種類以上定義されています。Unicode プログラミングの書籍で詳しく学べます。
結合文字の存在により、見た目が同じ文字でもコードポイント列が異なる場合があります。「á」は合成済み文字 U+00E1 (NFC 形式) としても、基底文字 U+0061 + 結合文字 U+0301 (NFD 形式) としても表現できます。Unicode 正規化 (NFC で合成、NFD で分解) を使って統一的に扱う必要があり、文字列比較の前に正規化を行わないと、見た目が同じ文字列が「不一致」と判定される問題が発生します。
結合文字は複数重ねることも可能です。1 つの基底文字に複数の結合文字を付加して、上にアクセント、下にセディーユといった複合的な修飾を表現できます。極端な例として、1 つの基底文字に数十の結合文字を重ねる「ザルゴテキスト」と呼ばれる表現があり、テキスト処理やレンダリングの負荷テストに使われることがあります。
セキュリティの観点では、結合文字を悪用した視覚的なスプーフィング (見た目は同じだがコードポイント列が異なる文字列) が問題になることがあります。ユーザー名やドメイン名の検証では、正規化後の比較が必須です。
文字数カウントの観点では、結合文字は独立したコードポイントとしてカウントされるため、String.length の値と見た目の文字数が一致しません。「á」が NFD 形式の場合、コードポイント数は 2 ですが見た目は 1 文字です。書記素クラスタ単位でのカウントが、ユーザーの期待に最も近い結果を返します。文字処理アルゴリズムの書籍も参考になります。