Skip to content

如何判断某个字符串长度(要求支持表情)?

参考答案:

大家看到题目,可能首先想到的是 str.length 获取字符串的长度。

其实 JS 中的字符串长度是个奇怪的设定,很多编程语言,获取字符串的长度是得到字节长度,比如一个正常的汉字是两个字节,但在 js 中,'汉'.length 是 1 。看上去很方便,殊不知,这个特性埋下的坑。

比如:

😀 : '😀'.length 得到的是 2
𠮷 : '𠮷''.length 得到的也是 2

ES6 里添加了一个东西叫字符串迭代器,还添加了一个东西叫 unicode 正则模式,它们也不能直接统计字符数,而是可以把字符串拆成一个字符的数组,你可以间接的计算出字符个数。

使用字符串的Iterator统计长度,如下例子:

js
const testStr = '123 ' 
 
for(let c of testStr) { 
  console.log(c) 
} 
// 1 
// 2 
// 3 
//   
console.log([...testStr].length) 
// 4

使用 Array.from 替换,并且封装一下:

js
function unicodeLength(str) {
    return Array.from(str).length
}

题目要点:

在JavaScript中,传统的String.prototype.length属性返回的字符串长度是基于UTF-16代码单元的数目,而不是字符的“感知长度”(即用户所认为的字符数)。由于某些字符(特别是表情符号和一些其他Unicode字符)需要两个或更多的UTF-16代码单元来表示,直接使用.length可能不会得到预期的结果。

为了正确计算包含表情符号的字符串的“感知长度”,你可以使用Array.from()方法结合String.prototype.codePointAt()方法。codePointAt()方法返回给定索引处的字符的Unicode码点,这对于所有Unicode字符(包括表情符号)都是准确的。

下面是一个计算字符串“感知长度”的函数示例:

javascript
function getPerceivedLength(str) {
  // 使用Array.from()和String.prototype.codePointAt()的回调函数来迭代字符串
  // codePointAt()的第二个参数用于指示是否考虑整个字符(对于多码点字符)
  // 但由于Array.from()调用codePointAt()时默认传递索引,我们不需要显式设置第二个参数
  // 直接获取所有码点,并计算其数量
  return Array.from(str, c => c.codePointAt(0)).length;
}

// 测试
const strWithEmoji = "Hello 🌍";
console.log(strWithEmoji.length); // 可能输出 7,因为🌍可能由两个UTF-16代码单元组成
console.log(getPerceivedLength(strWithEmoji)); // 输出 6,正确表示了字符串的“感知长度”

const strWithMultiEmoji = "👨‍👩‍👧‍👦"; // 家庭:男人、女人、女孩、男孩
console.log(strWithMultiEmoji.length); // 可能输出 8 或更多,因为每个角色可能由多个UTF-16代码单元组成
console.log(getPerceivedLength(strWithMultiEmoji)); // 输出 1,因为这是一个单独的“感知字符”