为什么一个只包含一个表情符号的字符串,像"",长度为2?

23

请查看http://developer.teradata.com/blog/jasonstrimpel/2011/11/javascript-string-length-and-internationalizing-web-applications。 - str
3个回答

21
JavaScript使用UTF-16(来源)来管理字符串。
在UTF-16中,有1,112,064个可能的字符。现在,每个字符使用码点来表示(*). 在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)


我认为只有ES2015在引擎和语言层面上都使用UTF-16。ES5使用UCT-2进行编码(至少在语言层面上是这样)。此外,每个字符只有一个代码点(从0x0到0x10FFFF),由一个或两个代码单元表示。因为string.length将代码单元解释为单个字符,所以对于BMP之外的字符计算出错误的结果。 - user6445533
据我所知,ES5 也使用 UTF-16:当一个字符串包含实际文本数据时,每个元素被视为单个的 UTF-16 代码单元。 https://es5.github.io/ - rpadovani
1
哦,我的错误。它被称为UCS-2,ES5引擎可以使用它们中的任何一个(UCS-2/UTF-16)。 - user6445533
@LUH3417 请随意改进我的回答 :) - rpadovani
有关ES2015中的Unicode,请参见以下链接:http://exploringjs.com/es6/ch_unicode.html - user6445533

14

我相信rpadovani最好地回答了你的“为什么”问题,但对于在此情况下获得正确字形计数的实现,Lodash已经在其toArray模块中解决了这个问题。

例如,

_.toArray('12').length; // --> 3

或者,如果您想从字符串中删除一些任意的字符,可以通过操作和重新连接数组来实现,例如:

_.toArray("trimToEightGlyphs").splice(0,8).join(''); // --> 'trimToE'

我本来以为lodash是一个宝可梦的名字。 - qwr
这可以使用本地JS完成,不需要额外的lodash依赖项:Array.from('12').length // --> 3 - imolit
Array.from() 对于所有的表情符号都不起作用。请尝试这个 console.log(Array.from("12‍‍").length); - Anjan Talatam

9
我发现了一个简单的方法来得到正确的结果。
这就是它:
'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 表示“全局”:基本上允许在第一个匹配后继续匹配。
u 表示“Unicode”:它允许以正确的方式显示字符(如果没有它,则会显示为��(因此是2个字符))

顺便说一下,你可以添加 m 来支持多行匹配(/./gum

希望这有所帮助


4
并非所有情况都适用。例如,"‍❤️‍‍".match(/./gu).length 的输出为 8。 - Brian K.
1
根据@BrianK.的观点,我相信有些人会寻求如何将其视为“一个”的答案,但这实际上正是我需要的,因为这确实是8个字符(将其粘贴到支持Unicode的测试编辑器中,然后开始按Backspace键,你会看到那里面有什么!),这正是MySQL varchar字段所需的“字符”数量。因此,如果您想在插入之前检查它是否适合您的数据库-这可能是您想要的。 - SmxCde
它不会将所有表情符号视为一个字符。例如️是2个字符,而‍❄️是4个字符。 - talhasch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接