文字数のカウントが正確なWebサイトは少ないので注意

文字数のカウントが正確なWebサイトは少ない

普段何気なく利用しているお問い合わせフォームなどの文字数のカウンター。

実は、世の中のほとんどのWebサイトで文字数が正しくカウントされていません。

例えば、「吉𠮷👩🏾‍🚀👨‍👩‍👧‍👦」を入力フォームにペーストするとサイトによってカウント数が異なります。

人間の目には「4文字」にしか見えませんが、JavaScriptのlengthプロパティでカウントすると21になります。

JavaScript
console.log(('吉𠮷👩🏾‍🚀👨‍👩‍👧‍👦'.length)) // 21

サイトによってはスプレッド構文やArray.fromとlengthを組み合わせていますが、これらもlengthが13になるので正確にカウントできません。

JavaScript
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を使用するのが最も適切です。

JavaScript
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を導入することを検討しましょう。