【发布时间】:2016-11-15 16:03:25
【问题描述】:
我的浏览器中的任何文本区域如何处理看似 2 个表示为一个字符的字符?
例如:
"????".length
// -> 2
【问题讨论】:
标签: javascript utf-8 emoji
我的浏览器中的任何文本区域如何处理看似 2 个表示为一个字符的字符?
例如:
"????".length
// -> 2
【问题讨论】:
标签: javascript utf-8 emoji
Javascript 使用UTF-16 (source) 来管理字符串。
在 UTF-16 中有 1,112,064 个可能的字符。现在,每个字符都使用code points 来表示(*)。在 UTF-16 中,一个代码点使用两个字节(16 位)来保存。这意味着使用一个代码点,您可以仅拥有 65536 个不同的字符。
这意味着某些字符必须用两个代码点表示。
String.length() 返回字符串中的代码单元数,而不是字符数。
MDN很好地解释了页面上关于String.length()的事情
此属性返回字符串中的代码单元数。 JavaScript 使用的字符串格式 UTF-16 使用一个 16 位的代码单元来表示最常见的字符,但对于不常用的字符需要使用两个代码单元,所以长度返回的值可能为与字符串中的实际字符数不匹配。
(*):实际上,在 010000 – 03FFFF 和 040000 – 10FFFF 范围内的某些字符每个代码点最多可以使用 4 个字节(32 位),但是这不会改变答案:有些字符需要超过 2 个字节才能表示,因此它们需要超过 1 个代码点。
这意味着一些需要超过 16 位的字符的长度无论如何都是 1。和0x03FFFF一样,需要21位,但在UTF-16中只使用了一个编码单元,所以它的String.length为1。
console.log(String.fromCharCode(0x03FFFF).length)
【讨论】:
string.length 将代码单元解释为单个字符,所以它会为基本多语言平面 (BMP) 之外的字符计算错误的结果。
When a String contains actual textual data, each element is considered to be a single UTF-16 code unit.es5.github.io
我相信 rpadovani 最好地回答了您的“为什么”问题,但是为了在这种情况下为您提供正确的字形计数的实现,Lodash 在他们的 toArray 模块中解决了这个问题。
例如,
_.toArray('12?').length; // --> 3
或者,如果您想从字符串中剔除几个任意字符,您可以操作并重新加入数组,例如:
_.toArray("?trimToEightGlyphs").splice(0,8).join(''); // --> '?trimToE'
【讨论】:
我找到了一种获得正确结果的简单方法。
这里是:
'?Some text with emojis?'.match(/./gu)
它应该返回:
[ "?","S", "o", "m", "e", " ", "t", "e", "x", "t", " ", "w", "i", "t", "h", " ", "e", "m", "o", "j", "i", "s", "?"]
然后你可以在上面申请.length:
'?'.match(/./gu).length == 1
它使用正则表达式匹配:/./gu
. 匹配任何单个字符。 g mean 'global' : 它基本上允许在第一场比赛后不停止。 u 意思是 'unicode' :它允许以正确的方式显示字符(没有它 ? 将显示为 ��(所以 2 个字符))
顺便说一句,您可以添加 m 以支持多行 (/./gum)
希望对您有所帮助 ?
【讨论】:
"?❤️??".match(/./gu).length 输出 8