JavaScriptでの正確な文字数カウント(サロゲートペア・絵文字・Intl.Segmenter)
JavaScript 文字コード Unicode 開発効率
JavaScript で文字列の長さを取得する際、絵文字(サロゲートペア・結合文字)によって発生する文字数カウントの不一致の原因と、正しい実装コードです。
1. オンライン文字数・原稿用紙換算・バイト数 カウントツール
入力されたテキストの見た目の文字数、UTF-8 バイト数、単語数、行数をブラウザ内で即座に測定します。
🔢 この場で文字数をカウントする
文字数
0
行数
0
単語数(スペース区切り)
0
バイト数(UTF-8)
0
2. なぜ str.length では絵文字の数がズレるのか?
JavaScript の文字列は内部的に UTF-16 で表現されており、string.length プロパティは「見た目の文字数」ではなく UTF-16 コードユニット(16ビット)の数 を返します。
| 文字 | str.length の値 | 理由 |
|---|---|---|
"A" | 1 | 基本多言語面(BMP)に含まれる通常の1バイト文字 |
"あ" | 1 | 1コードユニットで収まる文字 |
"🍎" (りんご) | 2 | 16ビットに収まらないためサロゲートペア(2コードユニット)で表現される |
"👨👩👧👦" (家族絵文字) | 11 | 4つの絵文字 + ZERO WIDTH JOINER (\u200D) の合成(結合文字) |
3. 正確な文字数を取得する 2 つの実装パターン
① モダンで最も確実:Intl.Segmenter (ES2022 / 推奨)
ブラウザおよび Node.js 16+ で利用可能な グラフェムクラスタ(人間が1文字として認識する単位) を分割してカウントする標準APIです。
function getGraphemeCount(text) {
// 日本語・絵文字に対応したグラフェムセグメンターを生成
const segmenter = new Intl.Segmenter('ja', { granularity: 'grapheme' });
const segments = segmenter.segment(text);
return Array.from(segments).length;
}
console.log(getGraphemeCount("🍎abc")); // 4 (正解)
console.log(getGraphemeCount("👨👩👧👦")); // 1 (正解)
② 簡易版:スプレッド構文 ([...str]) または Array.from()
サロゲートペア単体の文字(🍎 や 𩸽 等)であれば、Code Point 単位で分解する配列化で対応可能です(※結合文字 👨👩👧👦 は除きます)。
const text = "🍎abc";
// ❌ 単純な .length
console.log(text.length); // 5 (絵文字が2文字扱い)
// ✅ スプレッド構文で Code Point 分割
console.log([...text].length); // 4
console.log(Array.from(text).length); // 4
4. バイト数(UTF-8)の計算方法
RDBの VARCHAR(N) 制限やファイル保存で必要な「UTF-8バイト長」の計測コードです。
// ブラウザ標準の TextEncoder を使用
function getUtf8ByteLength(text) {
return new TextEncoder().encode(text).length;
}
console.log(getUtf8ByteLength("あ")); // 3 (UTF-8では日本語は3バイト)