我有这个 Unicode 字符串: Ааа́Ббб́Ввв́Г㥴Дд
我想用字符分割它。现在,如果我尝试循环所有字符,我会得到如下信息:
A a a ' Б ...
有没有办法将此字符串正确拆分为字符: А а а́
?
我有这个 Unicode 字符串: Ааа́Ббб́Ввв́Г㥴Дд
我想用字符分割它。现在,如果我尝试循环所有字符,我会得到如下信息:
A a a ' Б ...
有没有办法将此字符串正确拆分为字符: А а а́
?
要正确执行此操作,您需要的是用于计算字素簇边界的算法,如UAX 29中所定义。不幸的是,这需要从 Unicode 字符数据库中了解哪些字符是哪些类的成员,而 JavaScript 不提供该信息(*)。因此,您必须在脚本中包含 UCD 的副本,这会使其变得非常庞大。
如果您只需要担心拉丁语或西里尔语使用的基本重音,另一种选择是仅使用组合变音符号块 (U+0300-U+036F)。对于其他语言和符号,这将失败,但对于您想要做的事情可能就足够了。
function findGraphemesNotVeryWell(s) {
var re= /.[\u0300-\u036F]*/g;
var match, matches= [];
while (match= re.exec(s))
matches.push(match[0]);
return matches;
}
findGraphemesNotVeryWell('Ааа́Ббб́Ввв́Г㥴Дд');
["А", "а", "а́", "Б", "б", "б́", "В", "в", "в́", "Г", "г", "Ґ", "ґ", "Д", "д"]
(*:可能有一种方法可以通过让浏览器呈现字符串并测量其中选择的位置来提取信息......但它肯定会非常混乱且难以跨浏览器工作。)
对此有一点更新。
随着 ES6 的到来,出现了新的字符串方法和处理字符串的方法。对于其中存在的两个问题有解决方案。
表情符号和其他超出基本多语言平面 (BMP) 的 Unicode 字符(范围内的 Unicode“码点” 0x0000 - 0xFFFF
)可以计算出来,因为 ES6 中的字符串遵循迭代器协议,所以你可以这样做:
let textWithEmoji = '\ud83d\udc0e\ud83d\udc71\u2764'; //horse, happy face and heart
[...textWithEmoji].length //3
for (char of textWithEmoji) { console.log(char) } //will log 3 chars
当您开始使用“字素簇”(一个字符和它的变音符号)时,这是一个更难解决的问题。在 ES6 中,有一种方法可以简化它的工作,但它仍然很难工作。该String.prototype.normalize
方法简化了工作,但正如Mathias Bynens所说:
(A) 应用了多个组合标记的代码点总是会产生单个视觉字形,但可能没有规范化的形式,在这种情况下规范化没有帮助。
可以在这里找到更多见解:
https://ponyfoo.com/articles/es6-strings-and-unicode-in-depth https://mathiasbynens.be/notes/javascript-unicode
这个包可能会帮助你: https ://www.npmjs.com/package/runes
const runes = require('runes')
const example = 'Emoji '
example.split('') // ["E", "m", "o", "j", "i", " ", "�", "�"]
runes(example) // ["E", "m", "o", "j", "i", " ", ""]
如果您正在编写一个需要使用来自 Node.js 的数据块的应用程序stream
,那么您可能只需通过管道utf8-stream
来防止这种情况发生:
使用 Unicode 属性Grapheme_Base
"Ааа́Ббб́Ввв́Г㥴Дд".match(/\p{Grapheme_Base}/gu)
> ['А', 'а', 'а', 'Б', 'б', 'б', 'В', 'в', 'в', 'Г', 'г', 'Ґ', 'ґ', 'Д', 'д']
"Ааа́Ббб́Ввв́Г㥴Дд".match(/\p{Grapheme_Extend}/gu)
> ['́', '́', '́']
将这些组合成
"Ааа́Ббб́Ввв́Г㥴Дд".match(/\p{Grapheme_Base}\p{Grapheme_Extend}|\p{Grapheme_Base}/gu)
> ['А', 'а', 'а́', 'Б', 'б', 'б́', 'В', 'в', 'в́', 'Г', 'г', 'Ґ', 'ґ', 'Д', 'д']
您的字符串的问题是代理对(“a”“́)仅在浏览器显示时才组合为符号字符。对于您的情况,如果将 \u0301 附加到前一个字符就足够了,但这绝不是一般解决方案。
var a="Ааа́Ббб́Ввв́Г㥴Дд",
i =0,
chars=[];
while(a.charAt(i)) {
if (a.charAt(i+1) == "\u0301") {
chars.push(a.charAt(i++)+a.charAt(i++));
} else {
chars.push(a.charAt(i++));}}
要澄清这个问题,请阅读Mathias Bynens 的博文。