UTF-8 の文字数とバイト数の違い
UTF-8 では 1 文字のバイト数がアルファベット・漢字・絵文字で違います。Twitter のような「文字数」と JSON の「バイト数」の齟齬を解説します。
公開 · 更新 · yuzlrin
UTF-8 のバイト長
UTF-8 は可変長符号化で、Unicode の符号位置に応じてバイト数が変わります:
・U+0000 〜 U+007F (ASCII): 1 バイト(a、1、スペース)
・U+0080 〜 U+07FF: 2 バイト(é、ñ)
・U+0800 〜 U+FFFF: 3 バイト(あ、漢)
・U+10000 〜 U+10FFFF: 4 バイト(🎉、𠀋)
絵文字の多くは 4 バイトで、肌色修飾子付きや家族絵文字はサロゲートペア + 修飾で 8 バイト以上になります。
「文字数」の定義のブレ
「文字数」は文脈で 3 つの意味があります:
・Code Unit 数: JS の string.length。UTF-16 単位。「🎉」は 2。
・Code Point 数: Array.from(string).length。Unicode スカラー値。「🎉」は 1。
・Grapheme Cluster 数: ユーザー視点の「1 文字」。Intl.Segmenter で取得。絵文字合字を 1 文字扱い。
Twitter は CJK を 2 重み付けする独自カウントを採用しています。
実務での対処
DB のカラム制限が BYTES 単位なら UTF-8 バイト数でバリデーション、文字数制限が UX 目的なら Grapheme Cluster で数えるのが自然です。
JSON.stringify した結果のバイト数は TextEncoder().encode(str).byteLength で正確に取得できます。
関連ツール
よくある質問
Shift_JIS と UTF-8 でバイト数は違う?
はい。Shift_JIS は ASCII 1 バイト、全角文字 2 バイト固定で、UTF-8(全角 3 バイト)より短くなります。ただし絵文字の多くや中国語簡体字は Shift_JIS 非対応で扱えません。
絵文字 1 文字は何バイト?
素の絵文字は UTF-8 で 4 バイト。家族絵文字 👨👩👧 は ZWJ で結合され 18 バイト超、肌色付き 👋🏼 は 8 バイト。見た目の 1 文字とバイト数は大きく違います。
Twitter の 140 文字制限はどの文字数?
Twitter は独自ルールで、CJK は 2 ウェイト、URL は 23 文字固定、絵文字は 2 ウェイトで計算します。本サイトの文字数カウンターにも Twitter モードがあり同じ計算ができます。