概要
JavaScript で Intl.Segmenter が標準化され、拡張書記素クラスター単位で文字列を扱えるようになりました。拡張書記素クラスターを扱う上での課題はサイズの上限がないことです。そのため、従来の文字列メソッドとの使いわけやサイズの上限を超える拡張書記素クラスターの扱いについて方針が必要になります。
文字列メソッドの使いわけ
- 部分文字列を取り出すときは拡張書記素クラスター単位
- 文字数の上限はコードポイントもしくはバイト単位
上述の通り、拡張書記素クラスターの上限のサイズはないので、データベースに保存するときはコードポイントもしくはバイトのサイズをチェックする必要があります。
文字数が変わる処理への注意
- 大文字小文字変換
- ユニコード正規化
- 不正なバイト列の置き換え
上述の処理では文字数が変わってしまう可能性があるので、文字数の上限チェックの際はこれらの処理も考慮する必要があります。
ファクトリ関数の定義
Intl.Segmenter にはスタティックファクトリメソッドが存在しないので、自分でファクトリ関数を定義する必要があります。
function createGraphemeSegment(str) {
return (new Intl.Segmenter(
navigator.language,
{granularity: "grapheme"}))
.segment(str);
}
拡張書記素クラスターのサイズの上限(ストリームセーフテキストフォーマット)
巨大な拡張書記素クラスターはアプリのクラッシュや画面を壊す手段になるので、Apple (MacOS や iOS) や C++ ライブラリの Boost.Text は拡張書記素クラスターのサイズの上限をコードポイント32個未満としています。この値はストリームセーフテキストフォーマットの仕様(UAX15-D3)に記載されています。
サイズの上限を超える拡張書記素クラスターの扱い
後続の装飾記号(ノンスターター)を代替文字(U+FFFD)に置き換えたり、削除する方法が考えられます。原則論としては削除はセキュリティの問題になる可能性があるので、代替文字に置き換えることが望ましいです(例 at\x80rack -> attack)。
自前で文字列関数を定義する場合、文字数の数え方の仕様を決める必要があります。ストリームセーフテキストフォーマットの仕様には「数字の2、1万のウムラウト、ドットビロー、数字の3」の文字数は「10003」とするという例が記載されているので、これを仕様とすることができます。言い換えると、上限のサイズを超えた拡張書記素クラスターは構成するコードポイントの数で数えるということです。