#翻译# 深刻JavaScript的Unicode难题(上)

退一步说, JavaScript处理Unicode时有些怪异. 这篇文章会说明JS在Unicode上使人痛苦的部分, 而后提供解决方案, 并说明在将来的ECMAScript6中是如何改善这些问题的.
 
Unicode基础知识
为了您能更好的理解Unicode在JavaScript里的问题, 先确保你们了解Unicode为什么物.
最简单的咱们能够把 Unicode 想像成一个数据库, 任何您能想到的符号都对应着一个数字(咱们把这个数字叫作它的码位)和一个惟一的名字. 这样一来, 咱们能够方便的引用一个符号, 而没必要直接使用这个符号自己.
例如:
A U+0041 LATIN CAPITAL LETTER A
a U+0061 LATIN SMALL LETTER A
© U+00A9 COPYRIGHT SIGN
U+2603 SNOWMAN
U+1F4A9 PILE OF POO
 
码位一般用16进制数字表示, 用0补位, 至少4位数加上 U+ 前缀.
码们的范围是从U+0000至U+10FFFF. 能够表示110万个以上的符号.为了良好的组织如此庞大的数据, Unicode把这些码们分红了17个平面, 大约每一个平面包含了6.5万个码位.
第一部分也是最重要的部分叫作基本多文种平面或BMP, 这部分包含了咱们一般会用到的符号. 在英文文本文档中一般来讲您只须要使用BMP就足够了.
BMP以外还剩下100万个可用码位..包含这100万个码位的平面叫作补充平面星际平面.
星际平面十分容易辨识: 当您须要使用大于4位的16进制数来表示码位时, 这个码位就是星际码位.
如今咱们已经了解了Unicode基础知道, 下面来看看它是如何应用到JavaScript的字符串里的.
 
转义序列
您以前可能见过下面这些东西:
>> '\x41\x42\x43'
'ABC'
>> '\x61\x62\x63'
'abc'

 

这些叫作16进制转义序列. 它们包含2位16进制数字表示码位. 好比, '\x41' 表示 U+0041 LATIN CAPITAL LETTER A. 细心的读者可能发现了, 这些转义序列能够表示U+0000至U+00FF的码位.
 
还有一种常见的转义:
>> '\u0041\u0042\u0043'
'ABC'
>> 'I \u2661 JavaScript!'
'I ♡ JavaScript!'

 

这些叫作Unicode转义序列. 它们使用4位16进制数表示一个码位. 好比: '\u2661' 表示 U+2661 WHITE HEART SUIT. 这些转义序列表示的范围是U+0000至U+FFFF, 包含了所有的BMP.
 
那么对于其它平面呢? 好比星际平面? 咱们须要4位以上的16进制数才能表示它们的码位... 如何来转义??
 
在 ECMAScript 6 里, 这个很简单, 由于添加了一种新的转义方式: Unicode码位转义.
例如:
>> '\u{41}\u{42}\u{43}'
'ABC'

>> '\u{1F4A9}'
'' // U+1F4A9 PILE OF POO

 

(好吧.. 个人编辑器已经显示不了 PILE OF POO 了 - -!). 在大括号以前你可使用最多6位16进制数, 能够表示出全部的Unicode码位.
为了向后兼容ECMAScript5和更早的环境, 一个很差的方案就是使用替代组合:
>> '\uD83D\uDCA9'

'' // U+1F4A9 PILE OF POO

 

由二者组成一个星际符号. 要注意的是这两个组成部分已经失去了它们自己的码位意义.
使用这种替代组合后, 全部的星际码位均可以被表示了.. 你们应该已经感受到了, 单个码位能够表示的BMP与须要替代组合才能表示的星际符号混在一块儿, 使人困惑, 甚至会形成讨厌的后果.
在JavaScript里计算字符数
若是你想计算字符串的长度你会怎么作?
我首先想到的是用 length 属性.
>> 'A'.length // U+0041 LATIN CAPITAL LETTER A
1

>> 'A' == '\u0041'
true

>> 'B'.length // U+0042 LATIN CAPITAL LETTER B
1

>> 'B' == '\u0042'
true

 

上面的例子里, length 属性确实表示了字符的数量. (这说得通, 由于若是咱们使用转义序列来表示这个字符, 只须要一个转义就能够(\u0041 表示 A)).
来看一个不同的例子:
 
  
>> '퐀'.length // U+1D400 MATHEMATICAL BOLD CAPITAL A
2
>> '퐀' == '\uD835\uDC00'
true
>> '퐁'.length // U+1D401 MATHEMATICAL BOLD CAPITAL B
2
>> '퐁' == '\uD835\uDC01'
true
>> ''.length // U+1F4A9 PILE OF POO
2
>> '' == '\uD83D\uDCA9'
true
 
  
在JavaScript内部, 使用上文提到的替代组合来表示星际字符, 而且暴露出组成替代组合的2个字符. 若是你使用ECMAScript 5兼容的转义序列来表示符号, 就须要2个转义字符来表示一个星际符号. 这使人困惑, 由于人们一般是以一个Unicode符号或字母的一个总体来考虑它们, 而不是把一个星际字符想成2部分.
(未完待续)
相关文章
相关标签/搜索