Unicode in JavaScript
by Jinya
【转载请注明出处,http://blog.csdn.net/EI__Nino】
名词解释:
BMP:(BasicMultilingual Plane)它又简称为"零号平面", plane 0
UCS:通用字符集(Universal Character Set, UCS)
ISO:国际标准化组织(ISO)
UTF:UCS Transformation Format,
BOM:Byte Order Mark 字节序
CJK: 统一表意符号 (CJK Unified Ideographs)
BE:Big Endian 大端
LE:Little Endian 小端
一、简介
Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。1990年开始研发,1994年正式公布。
二、UCS
通用字符集(UniversalCharacter Set, UCS)是由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所定义的标准字符集。UCS-2用两个字节编码,UCS-4用4个字节编码。
UCS-4根据最高位为0的最高字节分成27=128个group。每个group再根据次高字节分为256个平面(plane)。每个平面根据第3个字节分为256行 (row),每行有256个码位(cell)。group 0的平面0被称作BMP(Basic MultilingualPlane)。如果UCS-4的前两个字节为全零,那么将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。
三、Unicode
Unicode标准准备把康熙字典的所有汉字放入到Unicode 32bit编码中。
Unicode扩展自ASCII字元集。在严格的ASCII中,每个字元用7位元表示,或者电脑上普遍使用的每字元有8位元宽;而Unicode使用全16位元字元集。这使得Unicode能够表示世界上所有的书写语言中可能用於电脑通讯的字元、象形文字和其他符号。Unicode最初打算作为ASCII的补充,可能的话,最终将代替它。考虑到ASCII是电脑中最具支配地位的标准,所以这的确是一个很高的目标。
Unicode影响到了电脑工业的每个部分,但也许会对作业系统和程序设计语言的影响最大。从这方面来看,我们已经上路了。Windows NT从底层支持Unicode(不幸的是,Windows 98只是小部分支援Unicode)。先天即被ANSI束缚的C程序设计语言通过对宽字元集的支持来支持Unicode。
四、UTF-8
字节FF和FE在UTF-8编码中永远不会出现,因此他们可以用来表明UTF-16或UTF-32文本(见BOM) UTF-8 是字节顺序无关的。
UTF-8以字节为单位对Unicode进行编码。从Unicode到UTF-8的编码方式如下:
Unicode编码(十六进制) |
UTF-8 字节流(二进制) |
000000 - 00007F |
0xxxxxxx (7x) |
000080 - 0007FF |
110xxxxx 10xxxxxx (11x) |
000800 - 00FFFF |
1110xxxx 10xxxxxx 10xxxxxx (16x) |
010000 - 10FFFF |
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx (21x) |
UTF-8的特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符,处于0号平面,BMP,UTF-8编码与ASCII编码完全相同。
-> “\x32" 2 -> "\u0032" "2"
UTF-8编码的最大长度是4个字节。从上表可以看出,4字节模板有21个x,即可以容纳21位二进制数字。
Unicode的最大码位0x10FFFF也只有21位。
例1:"汉"字的Unicode编码是0x6C49。0x6C49在0x0800-0xFFFF之间,使用用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。
将0x6C49写成二进制是:0110
1100 0100 1001, 用这个比特流依次代替模板中的x,得到:11100110
10110001 10001001,即E6 B1 89。
-> encodeURI(“汉") “%E6%B1%89"
例2:Unicode编码0x20C30在0x010000-0x10FFFF之间,使用用4字节模板了:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx。将0x20C30写成21位二进制数字(不足21位就在前面补0):0 0010 0000 1100 0011 0000,用这个比特流依次代替模板中的x,得到:11110000 10100000 10110000 10110000,即F0 A0 B0 B0。
五、The love between Javascript and Unicode
可以使用String.fromCharCode 方法从任意进制的数字转成字符串
\u加一个十六进制数字可以转成字符串
-> String.fromCharCode("0x4e01") "丁" -> 0x4e01.toString(10) "19969" -> String.fromCharCode(19969) "丁" -> "0x4e01".toString() "0x4e01" -> "\u4e01".toString() “丁" -> "\u4e01".toString() "丁"
六、输出
输出 "\u4e01"
->eval('"\u4e01"') "丁" == "\u4e01" -> "丁" ->eval(‘"丁"’) ->eval('"\\u4e01"') "丁" == "\\u4e01" -> "\u4e01" ->eval(‘"\u4e01"’) -> eval('"\\\u4e01"') "丁" == "\\\u4e01" -> "\丁" ->eval(‘"\丁"’) -> eval('"\\\\u4e01"') "\u4e01" == "\\\\u4e01" -> "\\u4e01" ->eval(‘"\\u4e01"’) ->'\u4e01' "丁" ->'\\u4e01' "\u4e01" ->'\\\u4e01' "\丁" ->'\\\\u4e01' "\\u4e01"
输出 "\丁"
-> "\丁" "丁" -> "\\丁" "\丁" -> "\\\丁" "\丁"
七、BOM
字节序有两种,分别是“大端”(Big Endian, BE)和“小端”(Little Endian, LE)。
根据字节序的不同,UTF-16可被实现为UTF-16LE或UTF-16BE,UTF-32可被实现为UTF-32LE或UTF-32BE。例如:
Unicode编码 |
UTF-16LE |
UTF-16BE |
UTF32-LE |
UTF32-BE |
0x006C49 |
49 6C |
6C 49 |
49 6C 00 00 |
00 00 6C 49 |
0x020C30 |
43 D8 30 DC |
D8 43 DC 30 |
30 0C 02 00 |
00 02 0C 30 |
Unicode标准建议用BOM(Byte Order Mark)来区分字节序,即在传输字节流前,先传输被作为BOM的字符“零宽无中断空格”。这个字符的编码是FEFF,而反过来的FFFE(UTF-16)和FFFE0000(UTF-32)在Unicode中都是未定义的码位,不应该出现在实际传输中。
下表是各种UTF编码的BOM:
UTF编码 |
Byte Order Mark (BOM) |
UTF-8 without BOM |
无 |
UTF-8 with BOM |
EF BB BF |
UTF-16LE |
FF FE |
UTF-16BE |
FE FF |
UTF-32LE |
FF FE 00 00 |
UTF-32BE |
00 00 FE FF |
八、讨论
为什么中文会占3个字节?
中文范围 4E00-9FBF:CJK 统一表意符号 (CJK Unified Ideographs)
unicode 编码 000800 - 00FFFF 内的UTF-8 二进制表示为:1110xxxx 10xxxxxx 10xxxxxx 。
英文是在ASCII里可以表示,而ASCII编码的表示和UTF-8编码完全相同。他们的范围在0x00-0x7F之间。
unicode 编码 000000 - 00007F 内的UTF-8 二进制表示为:0xxxxxxx 。
随机获取中文?
-> 0x4e00.toString(10) 19968 -> 0x9FBF.toString(10) 40895 -> 40895-19968 20927 String.fromCharCode(19968+Math.round(Math.random()*20927)
是否需要 BOM 头 ?
它的字节顺序在所有系统中都是一样的,因此它实际上并不需要BOM。但是PHP中,session创建前需要无输出,所以一般utf-8编码的php文件都要去除Bom头
HTML中的Unicode 和 javascript表示方法一样吗?
“&#” + unicode数字 得到对应的字符
document.write(“丁”) => 丁
document.write(“一”) =>丁
怎样查找中文?
-> “么么哒,memda".match(/[\u4e00-\u9FBF]/img) ["么", "么", "哒"]
长度?
->““么".length 1 ->"\u4e01".length 1
怎么从汉字获取到unicode编码?
-> “么”.charCodeAt(0).toString(16) "4e48" -> var a = “么么哒,meme” -> a.replace(/[\u4e00-\u9fbf]/img,function($){return "\\u"+$.charCodeAt(0).toString(16); }) "\u4e48\u4e48\u54d2,meme" -> parseInt(encodeURI(“丁").split("%").slice(1).map(function(v){return parseInt(v,16).toString(2).replace(/^1*0/,”"); }).join(""),2).toString(16) “4e01" == encodeURI(“丁”) => “%E4%B8%81" =>[“E4”,”B8”,”81”] => ["0100","111000", “000001"] =>”0100111000000001”=> 19969 =>”4e01"
参考:
http://www.cnblogs.com/ecalf/archive/2012/09/04/unicode.html
https://github.com/chenjinya/matrix