LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 568|回复: 0

变音符号和规范化

[复制链接]
发表于 2024-2-1 22:11:14 | 显示全部楼层 |阅读模式
很多语言都有由基础字符及其上方/下方的标记所组成的符号。

举个例子,字母 a 就是这些字符 àáâäãåā 的基础字符。

大多数常见的“复合”字符在 Unicode 表中都有自己的编码。但不是所有这些字符都有自己的编码,因为可能的组合形式太多了。

为了支持任意的组合,Unicode 标准允许我们使用多个 Unicode 字符:基础字符后跟着一个或多个“装饰”它的“标记”字符。

例如,如果我们在 S 后附加上特殊的“上方的点”字符(编码为 \u0307),则显示为 Ṡ。

alert( 'S\u0307' ); // Ṡ
如果我们需要在字母上方(或下方)添加一个额外的标记 —— 很简单,只需添加必要的标记字符即可。

例如,如果我们继续在后面附加一个“下方的点”符号(编码 \u0323),那么我们将得到一个“上下都有一个点符号的 S”:Ṩ。

就像这样:

alert( 'S\u0307\u0323' ); // Ṩ
这提供了极大的灵活性,但也带来了一个有趣的问题:两个字符可能在视觉上看起来相同,但却使用的是不同的 Unicode 组合。

举个例子:

let s1 = 'S\u0307\u0323'; // Ṩ, S + 上方点符号 + 下方点符号
let s2 = 'S\u0323\u0307'; // Ṩ, S + 下方点符号 + 上方点符号

alert( `s1: ${s1}, s2: ${s2}` );

alert( s1 == s2 ); // 尽管这两个字符在我们看来是相通的,但结果却是 false
“Unicode 规范化”算法可以解决这个问题,该算法将每个字符串转换为单一的“规范的”形式。

可以借助 str.normalize() 实现这一点。

alert( "S\u0307\u0323".normalize() == "S\u0323\u0307".normalize() ); // true
有意思的是,在我们这个例子中,normalize() 将 3 个字符的序列合并为了一个字符:\u1e68(带有上下两个点的 S)。

alert( "S\u0307\u0323".normalize().length ); // 1

alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true
但实际并非总是如此。出现这种情况的原因是符号 Ṩ 是“足够常见的”,所以 Unicode 创建者将其囊括在了 Unicode 主表中,并为其提供了对应的编码。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表