24

将 JavaScript 字符串拆分为“字符”可以轻松完成,但如果您关心 Unicode(并且您应该关心 Unicode),就会出现问题。

JavaScript 本机将字符视为 16 位实体(UCS-2 或 UTF-16),但这不允许BMP(基本多语言平面)之外的 Unicode 字符。

为了处理 BMP 之外的 Unicode 字符,JavaScript 必须考虑“代理对”,它本身并不这样做。

我正在寻找如何按代码点拆分 js 字符串,代码点是否需要一个或两个 JavaScript“字符”(代码单元)。

根据您的需要,按代码点拆分可能还不够,您可能希望按“字形集群”拆分,其中集群是一个基本代码点,后跟其所有非间距修饰符代码点,例如组合重音符号和变音符号

出于这个问题的目的,我不需要按字素簇拆分。

4

4 回答 4

33

@bobince 的回答(幸运的是)变得有点过时了;你现在可以简单地使用

var chars = Array.from( text )

获取尊重星体/32位/代理Unicode字符的单代码点字符串列表。

于 2017-03-04T14:03:01.767 回答
8

按照@John Frazer 的回答,可以使用这种更简洁的字符串迭代形式:

const chars = [...text]

例如,与:

const text = 'A\uD835\uDC68B\uD835\uDC69C\uD835\uDC6A'
const chars = [...text] // ["A", "", "B", "", "C", ""]
于 2018-09-26T22:51:58.613 回答
4

在 ECMAScript 6 中,您将能够使用字符串作为迭代器来获取代码点,或者您可以在字符串中搜索,或者您可以重复/./ug调用。getCodePointAt(i)

不幸的是for..of语法和正则表达式标志不能被 polyfill 并且调用 polyfillgetCodePoint()会非常慢(O(n²)),所以我们暂时还不能实际使用这种方法。

所以以手动方式进行:

String.prototype.toCodePoints= function() {
    chars = [];
    for (var i= 0; i<this.length; i++) {
        var c1= this.charCodeAt(i);
        if (c1>=0xD800 && c1<0xDC00 && i+1<this.length) {
            var c2= this.charCodeAt(i+1);
            if (c2>=0xDC00 && c2<0xE000) {
                chars.push(0x10000 + ((c1-0xD800)<<10) + (c2-0xDC00));
                i++;
                continue;
            }
        }
        chars.push(c1);
    }
    return chars;
}

与此相反,请参阅https://stackoverflow.com/a/3759300/18936

于 2014-01-28T15:03:31.107 回答
0

使用 codePointAt 的另一种方法:

String.prototype.toCodePoints = function () {
  var arCP = [];
  for (var i = 0; i < this.length; i += 1) {
    var cP = this.codePointAt(i);
    arCP.push(cP);
    if (cP >= 0x10000) {
      i += 1;
    }
  }
  return arCP;
}
于 2020-04-11T14:39:15.787 回答