在JavaScript字符串中获取字形字符数量?

11

我想要获取JavaScript字符串的长度,按照用户可见图形字符计算,即忽略组合字符(和代理对?)。是否有可能实现这一点,如果可以,如何实现?

我们在项目中使用dojo工具包,但任何通用的JavaScript解决方案都可以。


1
这个问题的答案:https://dev59.com/tG865IYBdhLWcg3wlviq 包括了有用的信息,即javascript使用UCS-2而不是UTF-16,并指出这是不可能的。 - Angus
这是可能的,只是不容易,因为你必须处理一些低级别的Unicode问题。 - hippietrail
请将包含表情符号的字符串拆分为数组的方法告诉我。 - Rúnar Berg
1
这个回答解决了你的问题吗?如何将包含表情符号的字符串拆分成数组? - Stefnotch
5个回答

8

以下是一款纯JavaScript库,专门用于此目的:

https://github.com/orling/grapheme-splitter

它实现了Unicode UAX-29标准,包括你可能会在自己编写解决方案时忽略的非拉丁语言重音符号、韩文jamo字符、表情符号、多个组合符号等所有边缘情况。


6

使用Intl.Segmenter

Intl.Segmenter对象实现了区域敏感的文本分割,使您能够从字符串中获取有意义的项(字形、单词或句子)。

[...new Intl.Segmenter().segment('️‍⚧️️‍‍❤️‍')].length;
//=> 3

"️‍⚧️️‍‍❤️‍".length
//=> 24

[..."️‍⚧️️‍‍❤️‍"].length
//=> 17

截至2023年3月,Intl.Segmenter在Node、Chrome和Safari中可用,但在Firefox中不可用(请查看可用性表格这里提供了polyfill)。

2

将字符串拆分为数组

然后计数

let arr = [..."⛔"] // ["", "", "", "⛔", "", "", ""]
let len = arr.lenght

感谢 downGoat 的贡献。

请注意,这个解决方案在某些特殊情况下无法正常工作,例如下面的注释中一个表情符号由四个字符组成:[..."‍‍‍"] -> ['', '‍', '', '‍', '', '‍', '']

尽管我将其发布在这里供 Google 搜索使用,因为对于大多数情况而言它都有效,并且比其他所有替代方案都要简单得多。

完整解决方案

为了克服上面那种特殊的表情符号,可以搜索连接字符并进行一些修改。该字符的字符代码为8205(UTF-16)。以下是具体操作:

let myStr = "‍‍‍"
let arr = [...myStr]

for (i = arr.length-1; i--; i>= 0){
    if (arr[i].charCodeAt(0) == 8205) { // find & handle special combination character
        arr[i-1] += arr[i] + arr[i+1];
        arr.splice(i, 2)
    }
}
console.log(arr.length) //2

我还没有遇到这个不起作用的情况。如果你遇到了,请评论。

3
[..."‍‍‍"] -> ['', '‍', '', '‍', '', '‍', ''] - Gene S

1

关于组合字符,请查看派生组合等级,其中列出了所有的组合字符(以及其他字符)。由于您只是对计数感兴趣,您可以将它们删除——这样就能得到稍微更接近的估计。

在Angus发布的帖子中, JavaScript字符串在BMP之外显示了处理代理项的代码。但实际上,该代码执行的与您想要的相反——它将0x10000+的代码点分成两个代码点。就JS而言,它是一个代码点——虽然是截断的代码点。谁在乎呢?你在计数,而不是显示......

但是,还有另一类代码点也可能需要处理,那就是不可打印字符。当然,任何低于0x20的字符都是不可见的,但还有很多其他字符——例如查看0x2000范围。这些字符也不可见,不应计入您的计数。


谢谢你提供的信息,当时我没有注意到链接的问题中有示例代码,我看了一遍,以为 JS 无法处理必要的低级字符串操作。 - Angus

0

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