
文字数のカウントが正確なWebサイトは少ない
普段何気なく利用しているお問い合わせフォームなどの文字数のカウンター。
実は、世の中のほとんどのWebサイトで文字数が正しくカウントされていません。
例えば、「吉𠮷👩🏾🚀👨👩👧👦」を入力フォームにペーストするとサイトによってカウント数が異なります。
人間の目には「4文字」にしか見えませんが、JavaScriptのlengthプロパティでカウントすると21になります。
console.log(('吉𠮷👩🏾🚀👨👩👧👦'.length)) // 21サイトによってはスプレッド構文やArray.fromとlengthを組み合わせていますが、これらもlengthが13になるので正確にカウントできません。
console.log([...'吉𠮷👩🏾🚀👨👩👧👦'].length) // 13
console.log(Array.from('吉𠮷👩🏾🚀👨👩👧👦').length) // 13なぜこのようなことが起きるのか?
JavaScriptのlengthが返しているのは「人間が見た文字の数」ではなく、「UTF-16のコード単位の数」です。
基本的な文字は16ビット(1コードユニット)で表現できますが、「𠮷」や「😀」などの文字は32ビット(2コードユニット)必要なため、lengthは「2」になります。
さらに複雑な絵文字(例: 👨👩👧👦)は「男性(2)」「ZJW(結合用記号: 1)」「女性(2)」「ZJW(1)」「女の子 (2)」「ZJW(1)」「男の子 (2)」といった、複数の絵文字や制御文字が合体して1つの絵文字として描写されています。
そのため、内部のコードユニット数が加算され「11」になってしまいます。
正しく文字数をカウントするには?
人間が認識する「見た目の1文字」を正確に1文字としてカウントするには、JavaScriptのIntl.Segmenterを使用するのが最も適切です。
const segmenter = new Intl.Segmenter('ja')
const count = (str) => {
return [...segmenter.segment(str)].length
}
console.log((''.length)) // 0
console.log((' '.length)) // 1
console.log(('吉'.length)) // 1
console.log(count('𠮷')) // 1
console.log(count('😀')) // 1
console.log(count('👩🏾🚀')) // 1
console.log(count('👨👩👧👦')) // 1
console.log(count('吉𠮷👩🏾🚀👨👩👧👦')) // 4日本語のテキストを正確にカウントするツール
Web上には日本語のテキストをカウントするツールがいくつかありますが、内部のコードユニット数が多い複雑な絵文字やバイト数なども含めて正確にカウントできるのは、以下の「文字数カウンター🔡」だけなので注意が必要です。
まとめ
入力フォームや文字数カウンターを実装する際、単にlengthを使うだけでは正確にカウントできません。
最近は2コードユニット以上の漢字や絵文字が入力フォームに絵文字が入力されることがめずらしくなく、これが原因でクライアントやQAからバグとして報告を受けるケースが以前よりも増えています。
視覚的に正確な文字数カウントが必要な場面では、Intl.Segmenterを導入することを検討しましょう。



