Shn*_*ick 40 javascript string unicode iterator
我一直在玩 JS,但无法弄清楚 JS 如何决定在使用Array.from(). 例如,以下表情符号的 alength为 2,因为它由两个代码点组成,但是,Array.from()将这两个代码点视为一个,给出一个包含一个元素的数组:
const emoji = '';
console.log(Array.from(emoji)); // Output: [""]Run Code Online (Sandbox Code Playgroud)
但是,其他一些字符也有两个代码点,例如这个字符??(也有一个.length2)。但是,Array.from不会“分组”此字符,而是生成两个元素:
const str = '??';
console.log(Array.from(str)); // Output: ["?", "?"]Run Code Online (Sandbox Code Playgroud)
我的问题是:当字符由两个代码点组成时,是什么决定了字符是被分解(如示例二)还是被视为一个单一元素(如示例一)?
Cer*_*nce 27
Array.from首先尝试调用参数的迭代器(如果它有),而字符串确实有迭代器,所以它会调用String.prototype[Symbol.iterator],所以让我们看看原型方法是如何工作的。它在此处的规范中描述:
- 让 O 成为?RequireObjectCoercible(这个值)。
- 让 S 是?ToString(O)。
- 返回 CreateStringIterator(S)。
查找CreateStringIterator最终会将您带到21.1.5.2.1 %StringIteratorPrototype%.next ( ),它会:
- 让cp成为!CodePointAt(s, 位置)。
- 令 resultString 为包含 cp.[[CodeUnitCount]] 来自 s 的连续代码单元的字符串值,该代码单元从索引位置处的代码单元开始。
- 将 O.[[StringNextIndex]] 设置为位置 + cp.[[CodeUnitCount]]。
- 返回 CreateIterResultObject(resultString, false)。
这CodeUnitCount就是你感兴趣的。这个数字来自CodePointAt:
- 首先是字符串中索引位置的代码单元。
- 让 cp 是其数值为 first 的代码点。
如果 first 不是前导代理或尾随代理,则
一种。返回记录
{ [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: false }。如果 first 是尾随代理或位置 + 1 = 大小,则
a
{ [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }.返回记录。让 second 成为字符串中索引位置 + 1 处的代码单元。
如果 second 不是尾随代理,则
一种。返回记录
{ [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }。将 cp 设置为 ! UTF16DecodeSurrogatePair(第一,第二)。
返回记录
{ [[CodePoint]]: cp, [[CodeUnitCount]]: 2, [[IsUnpairedSurrogate]]: false }。
因此,当使用 迭代字符串时Array.from,仅当所讨论的字符是代理对的开头时,它才返回 CodeUnitCount 为 2。这里描述了被解释为代理对的字符:
此类操作对具有0xD800 到 0xDBFF范围内数值的每个代码单元(由 Unicode 标准定义为前导代理,或更正式地定义为高代理代码单元)和每个具有数值的代码单元进行特殊处理在 0xDC00 到 0xDFFF(定义为尾随代理,或更正式地定义为低代理代码单元)的包含范围内,使用以下规则..:
?? 不是代理对:
console.log('??'.charCodeAt()); // First character code: 2359, or 0x937
console.log('??'.charCodeAt(1)); // Second character code: 2367, or 0x93FRun Code Online (Sandbox Code Playgroud)
但是的字符是:
console.log(''.charCodeAt()); // 55357, or 0xD83D
console.log(''.charCodeAt(1)); // 56397, or 0xDC4DRun Code Online (Sandbox Code Playgroud)
的第一个字符代码''是十六进制的 D83D,在0xD800 to 0xDBFF前导代理的范围内。相比之下,的第一个字符代码'??'要低得多,而事实并非如此。所以'??'会分开,但''不会。
??由两个独立的字符组成:?,梵文字母 Ssa和?,梵文元音符号 I。当按此顺序彼此相邻时,尽管它们由两个单独的字符组成,但它们在视觉上会以图形方式组合成一个字符。
相比之下, 只有当作为单个字形组合在一起时,字符代码才有意义。如果您尝试使用带有任一代码点而没有其他代码点的字符串,您将得到一个无意义的符号:
console.log(''[0]);
console.log(''[1]);Run Code Online (Sandbox Code Playgroud)
这都是关于字符背后的代码。有些以两个字节 (UTF-16) 编码,并被解释Array.from为两个字符。必须检查字符列表:
http://www.fileformat.info/info/charset/UTF-8/list.htm
http://www.fileformat.info/info/charset/UTF-16/list.htm
function displayHexUnicode(s) {
console.log(s.split("").reduce((hex,c)=>hex+=c.charCodeAt(0).toString(16).padStart(4,"0"),""));
}
displayHexUnicode('??');
console.log(Array.from('??').forEach(x => displayHexUnicode(x)));Run Code Online (Sandbox Code Playgroud)
function displayHexUnicode(s) {
console.log(s.split("").reduce((hex,c)=>hex+=c.charCodeAt(0).toString(16).padStart(4,"0"),""));
}
displayHexUnicode('');
console.log(Array.from('').forEach(x => displayHexUnicode(x)));Run Code Online (Sandbox Code Playgroud)
对于显示十六进制代码的函数:
| 归档时间: |
|
| 查看次数: |
1266 次 |
| 最近记录: |