UTF-8 の文字数とバイト数の違い
UTF-8では文字の符号位置や結合列によりバイト数が異なります。UTF-16 code unit・Unicode code point・書記素クラスタの違いと、Xの加重文字数を説明します。
公開 · 更新 · yuzlrin
UTF-8 のバイト長
UTF-8 は可変長符号化で、Unicode の符号位置に応じてバイト数が変わります:
・U+0000 〜 U+007F (ASCII): 1 バイト(a、1、スペース)
・U+0080 〜 U+07FF: 2 バイト(é、ñ)
・U+0800 〜 U+FFFF(U+D800〜U+DFFFのサロゲート符号位置を除く): 3 バイト(あ、漢)
・U+10000 〜 U+10FFFF: 4 バイト(🎉、𠀋)
絵文字は符号化列により長さが異なります。🎉はUTF-8で4バイト、家族絵文字 👨👩👧 は複数の絵文字とZWJからなり18バイトです。UTF-16のサロゲートペア数とUTF-8のバイト数を混同しないでください。
「文字数」の定義のブレ
「文字数」は文脈で 3 つの意味があります:
・Code Unit 数: JS の string.length。UTF-16 単位。「🎉」は 2。
・Code Point 数: Array.from(string).length。「🎉」は 1。整形式のUnicode文字列ではUnicodeスカラー値の数に対応しますが、孤立サロゲートも数えるため入力の整形式性には注意が必要です。
・Grapheme Cluster 数: ユーザー視点の「1 文字」。Intl.Segmenter で取得。絵文字合字を 1 文字扱い。
Xの標準投稿カウントは280 weighted charactersで、CJKなどは2、URLは23として扱います。これはUTF-8 byte lengthや書記素クラスタ数とは異なる独自ルールです。
実務での対処
DB のカラム制限が BYTES 単位なら UTF-8 バイト数でバリデーション、文字数制限が UX 目的なら Grapheme Cluster で数えるのが自然です。
JSON.stringify した結果のバイト数は TextEncoder().encode(str).byteLength で正確に取得できます。
関連ツール
よくある質問
Shift_JIS と UTF-8 でバイト数は違う?
代表的なShift_JIS符号化ではASCIIは1バイト、半角カナも1バイト、一部の全角文字は2バイトです。文字集合はUTF-8と異なり、絵文字などは表現できない場合があります。
絵文字 1 文字は何バイト?
🎉はUTF-16 code unitで2、UTF-8で4バイトです。👨👩👧はZWJを含む列でUTF-8 18バイトです。👋🏼のように修飾子が加わる列も、実際の文字列をTextEncoderで数えてください。
Xの投稿文字数はどう数える?
現在のX投稿は標準で280 weighted charactersで数え、CJKなど一部文字は2、URLは23として扱う仕様です。実際のカウント規則は更新されることがあります。本サイトの文字数カウンターにXモードはありません。
出典・参考資料
本文は上記資料を参考にした解説です。仕様やサービスの運用は変更されることがあるため、実際の利用時は公式資料も確認してください。