JavaScript | サロゲートペア

JavaScript JavaScript
スポンサーリンク

サロゲートペアの正しい扱い方(絵文字対応)

1. 問題の本質:length や charAt() がズレる

JavaScript の String は UTF-16 単位で扱うため、サロゲートペアを「2文字」と数えることがあります。

const s = '💖'; // ハートの絵文字
console.log(s.length); // 👉 2
console.log(s.charAt(0)); // 上位サロゲート(文字化け)
console.log(s.charAt(1)); // 下位サロゲート(文字化け)
JavaScript

見た目では「💖」は1文字ですが、内部的には 2単位(2ワード)に分かれています。

2. 正しい扱い方の基本戦略

サロゲートペアを意識せずに安全に扱うには「コードポイント」を使う。

つまり:

  • codePointAt()(Unicodeコードポイント単位)を使う!
  • charCodeAt()(UTF-16単位)ではなく、
const s = '💖';
console.log(s.codePointAt(0).toString(16)); // 👉 '1f496'(💖のUnicodeコードポイント)
JavaScript

同様に、文字列を作るときも:

console.log(String.fromCodePoint(0x1f496)); // 💖
JavaScript

3. 絵文字を安全に1文字ずつ処理する方法

方法A:スプレッド構文(推奨)

const text = 'A💖B😊';
const chars = [...text]; // サロゲートペアを1文字として分割
console.log(chars); // 👉 [ 'A', '💖', 'B', '😊' ]
console.log(chars.length); // 👉 4(見た目通り)
JavaScript

方法B:Array.from()(同様の効果)

Array.from('A💖B😊'); // 👉 [ 'A', '💖', 'B', '😊' ]
JavaScript

これらは内部的に codePointAt() を利用しており、サロゲートペアを自動的に正しく扱います。

4. 絵文字対応の substring() / slice() の安全版

JavaScript 標準の slice() はサロゲートペアを途中で切ることがあります。
→ そこで、「見た目上の文字単位」で安全に切り出す関数を自作します。

function safeSlice(str, start, end) {
  return [...str].slice(start, end).join('');
}

const s = 'A💖B😊C';
console.log(safeSlice(s, 1, 3)); // 💖B
JavaScript

5. 文字単位で安全にループ処理する

for (const ch of '💖😊🍀') {
  console.log(ch);
}
JavaScript

for...of ループはサロゲートペアを自動的に1文字として処理してくれます。
for (let i = 0; i < str.length; i++) は NG)

6. 正しい長さを取得する (length の代替)

const emojiText = 'A💖B😊C';
console.log([...emojiText].length); // 5(見た目通りの文字数)
JavaScript

まとめ:安全な文字列処理セット

処理したいことNGな方法正しい方法
文字コードを取得charCodeAt()codePointAt()
文字を生成String.fromCharCode()String.fromCodePoint()
文字数を数える.length[...str].length
1文字ずつ処理for (let i...)for...of または Array.from()
部分文字列取得slice()safeSlice() 関数など

応用:サロゲートペア検出関数(レビュー用)

function hasSurrogatePair(str) {
  return /[\uD800-\uDBFF][\uDC00-\uDFFF]/.test(str);
}

console.log(hasSurrogatePair('💖')); // true
console.log(hasSurrogatePair('A'));  // false
JavaScript

実務Tips

  • 絵文字や多国語文字を扱うサービス(チャット・SNSなど)では必須の知識。
  • DB保存やAPI通信時に文字化け・長さ制限バグが出る原因は、ほぼこのサロゲートペアの扱いにある。
  • 「文字数上限(例:140文字)」を設定する時も、[...str].length でカウントすべき。

タイトルとURLをコピーしました