首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

JavaScript 字串長度:字元數 vs UTF-16 程式碼單元數

     編輯:程式設計綜合問答

核心結論

String.prototype.length 回傳的是 UTF-16 程式碼單元數,不是 使用者感知的字元數(grapheme clusters)。

為什麼會有誤解?

《JavaScript 權威指南》第 39 頁說明:JS 字串是 UTF-16 編碼序列。BMP 字元(U+0000 ~ U+FFFF)佔 1 個程式碼單元;補充平面字元(U+10000 ~ U+10FFFF)佔 2 個程式碼單元(surrogate pair)。

實測驗證

> 'e'.length                    // 1  (BMP 字元)
1
> '𝑒'.length                    // 2  (U+1D452 數學斜體小寫 e,補充平面)
2
> '😀'.length                   // 2  (Emoji U+1F600)
2
> '👨‍👩‍👧‍👦'.length              // 11 (家庭 Emoji:4 個基礎字元 + 3 個 ZWJ 連接符)
11

原始提問者的困惑

提問者看到 \ud835\udc52(這是 𝑒 的 UTF-16 代理對表示),以為是字母 e,實際上它是數學斜體小寫 e(MATHEMATICAL ITALIC SMALL E),屬於補充平面字元,故 length === 2。

正確取得「字元數」的方法

方案一:ES2015 Spread / Array.from(推薦,支援 surrogate pair)

const str = '𝑒😀ab';
[...str].length;        // 4
Array.from(str).length; // 4

方案二:正則表達式 u 模式(ES2015)

str.match(/[\s\S]/gu)?.length; // 4

方案三:Intl.Segmenter(ES2022,最語義正確)

const segmenter = new Intl.Segmenter('zh', { granularity: 'grapheme' });
[...segmenter.segment('👨‍👩‍👧‍👦')].length; // 1 (視為 1 個字素簇)
[...segmenter.segment('𝑒')].length;   // 1

對比表

字串.length[...str].lengthIntl.Segmenter
abc333
𝑒 (U+1D452)211
😀 (U+1F600)211
👨‍👩‍👧‍👦11111
é (e + 組合鋭音符)221

實務建議

  • 存儲/傳輸/截取:用 .length、substring、slice(按程式碼單元操作)
  • 顯示長度限制、字數統計:用 [...str].length 或 Intl.Segmenter
  • 表單驗證「最多 140 字」:建議用 Intl.Segmenter 符合使用者直覺
  • 資料庫 VARCHAR(n):n 指位元組或字元視編碼而定,切勿直接對應 JS .length

歷史背景

JS 設計時(1995)Unicode 僅有 BMP,UTF-16 固定 2 位元組/字元。後來 Unicode 擴展至補充平面,JS 為相容性保留 UTF-16 並引入 surrogate pair,導致 length 語義固化為「程式碼單元數」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved