用JavaScript和Python计算Unicode字符串的字节数
2009 3 6 12:04 AM 4023次查看
分类:编程 标签:JavaScript, Python
UTF-8的编码规则很简单,只有二条:
- 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
- 对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。
下面是Unicode转换到UTF-8的方法:
Unicode(16进制) | UTF-8 字节流(二进制) |
000000 - 00007F | 0xxxxxxx (1字节) |
000080 - 0007FF | 110xxxxx 10xxxxxx (2字节) |
000800 - 00FFFF | 1110xxxx 10xxxxxx 10xxxxxx (3字节) |
010000 - 10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx(4字节) |
方法如下:
function byteLength(s) {
var totalLength = 0;
var charCode;
for (var i = 0; i < s.length; ++i) {
charCode = s.charCodeAt(i);
if (charCode < 0x0080) {
++totalLength;
} else if (charCode < 0x0800) {
totalLength += 2;
} else if (charCode <= 0xffff) {
totalLength += 3;
} else {
totalLength += 4;
}
}
return totalLength;
}
当然,这是UTF-8编码。如果是GBK编码,只需要判断是否小于0x0080,小于为1字节,否则为2字节(由于字符数有限,不存在超过2字节的字符)。顺便说下Python中的方法。
Python的len也是计算字符数,但是如果用encode方法把Unicode转为GBK或UTF-8编码的字符串后,此时的len就是字节数了。
给个演示:
>>> s=u'好'
>>> len(s)
1
>>> len(s.encode('gbk'))
2
>>> len(s.encode('utf8'))
3
>>> s=u'Google vs 百度'
>>> len(s)
12
>>> len(s.encode('gbk'))
14
>>> len(s.encode('utf8'))
16
很显然,GBK编码比UTF-8编码要少占用空间,特别是用来记录中文时。不过准确来说,上文中我用的字符这个术语并不准确,所以顺便介绍一下code point。
Unicode中一共有1114112个code point。其中,代码点小于FFFF的属于基本多文种平面(Basic Multilingual Plane,简称BMP),包含在UCS-2中,可以用U+xxxx表示,Python里写为\uxxxx。而Unicode中还有其他16种辅助平面,这些平面的字符的代码点都超过FFFF,超出了UCS-2的范围,因此改用UCS-4,只能用U-xxxxxx来表示,Python里写为\U00xxxxxx。
一个code point可以对应一个Unicode字符或符号(glyph),但实际意义上的字符和Unicode字符却并非一一对应的。
例如这2个字符:Ä和Ä。虽然看上去很像,但它们是不同的code point组成的:前者是U+00C4,后者是U+0041 U+0308这2个code point的组合。
并非只有国外的字符才有这种情况,汉语拼音实际上也是如此,例如e和ˊ就可以组成é。
甚至还可以用任意多的code point组成一个蝌蚪文。
最后还得提到一点,那就是code unit。它指的是编码时采用的最小字符单位。
对C而言,一个code unit就是char,为1字节(在32位系统上为8位)。1或多个char组成一个Unicode字符,但这需要程序员自己去处理。你也可以用而w_char作为code unit,它可以表示一个UCS-2字符(BMP范围内),但并不能处理辅助平面的字符,因此需要自己实现UTF-16。
对Java而言,一个code unit就是char,为2字节(16位)。1个char可以表示一个UCS-2字符。Java 1.5以后增加了对UTF-16的支持,于是就变成可变长编码了,1或2个char可以表示一个UCS-4字符。但是处理辅助平面的字符时需要使用新增的API。
对Python而言,这是由编译时的参数决定的。较新的版本中,在Windows平台上采用的是UCS-2(准确来说是输入采用UTF-16,因为不存在UCS-2编码,而内部表示为UCS-2,因此一个UCS-4 code point可以表示为1或2个UCS-2 code unit),而Unix上则是UCS-4。在计算长度时,目前的实现是返回code unit的数量,而不是code point的数量。
然而无论哪种语言,都最多只能帮你做到code point这级,而不会帮你处理组合字符。
0条评论 你不来一发么↓