将JavaScript字符串拆分为代码点数组? (考虑到“代理对”而不是“字形群”)

时间:2014-01-28 05:09:52

标签: javascript string unicode codepoint surrogate-pairs

将JavaScript字符串拆分为"字符"可以琐碎地完成但是如果你关心Unicode会有问题(你应该关心Unicode)。

JavaScript本身将字符视为16位实体(UCS-2 or UTF-16),但这不允许BMP (Basic Multilingual Plane)之外的Unicode字符。

为了处理BMP之外的Unicode字符,JavaScript必须考虑到" surrogate pairs",它本身不会这样做。

我正在寻找如何通过代码点拆分js字符串,代码点是否需要一个或两个JavaScript"字符" (代码单位)。

根据您的需要,按codepoint拆分可能还不够,您可能希望按" grapheme cluster"拆分,其中群集是基本代码点,后跟所有非间距修饰符代码点,例如combining accents and diacritics

就本问题而言,我不需要通过字形集群进行拆分。

4 个答案:

答案 0 :(得分:17)

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

var chars = Array.from( text )

获取单一代码点字符串列表,该字符串确实遵循星体/ 32位/代理Unicode字符。

答案 1 :(得分:3)

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

不幸的是for .. of语法和regexp标志无法填充,调用polyfilled getCodePoint()会超级慢(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

答案 2 :(得分:2)

在@John Frazer的答案中,人们甚至可以使用这种甚至更简洁的字符串迭代形式:

AddString

例如,带有:

const chars = [...text]

答案 3 :(得分: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;
}