编码方式
- UTF8
- 单字节(byte)。目前使用1~4字节,变长编码,可以任意扩充,参考 RFC3629。 UTF16
- 双字节(word)。超过U+10000的编码以4字节编码。 UTF32
- 四字节。
Qt QString 和 Java String 内部是UTF16表示。UTF16有字节序要求,UTF8没有。
UTF-8编码
| Unicode内码范围(HEX) | UTF8串(BIN) |
|---|---|
0000 0000-0000 007F |
0xxxxxxx |
0000 0080-0000 07FF |
110xxxxx 10xxxxxx |
0000 0800-0000 FFFF |
1110xxxx 10xxxxxx 10xxxxxx |
0001 0000-0010 FFFF |
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
这里是一些常见字符的内码,更多可以参考Unicode内码表:
| 字符 | Unicode内码范围 |
|---|---|
| 0-9 | 0x30-0x39 |
| A-Z | 0x41-0x5A |
| a-z | 0x61-0x7A |
| Latin标点 | 0x21-0x2F 0x3A-0x40 0x5B-0x60 0x7B-0x7E |
| 一般标点 | 0x2000-0x206F |
| CJK标点 | 0x3000-0x303F |
| CJK字符 | 0x4E00-0x9FA5 |
| 全角字符 | 0xFF00-0xFFEF |
可见中文所属的CJK,最常用的内码范围是 0x4E00-0x9FA5,在0x0800-0xFFFF之间,所以会用三字节进行编码,补上一个1110,两个10,UCS-2中两字节的中文就变成了UTF-8的三字节。
以“中”字为例,Unicode内码0x4E2D的二进制是:
0100 1110 0010 1101
对照UTF-8模板:
1110xxxx 10xxxxxx 10xxxxxx
对号入座得到:
11100100 10111000 10101101
所以“中”字的UTF-8编码为:E4 B8 AD。
参考 U+4E00-U+9FFF 的码表,这里可以根据 Unicode 码查到所有的字符。
同时,也可以在正则表达式中使用 [\u4e00-\u9fa5] 来简单的判断中文字符。
编程处理
C++
C++中如果要处理中文字符,建议使用std::wstring,这样每个字都是wchar_t固定双字节长度,比较好操作。不过必须要设置locale:
std::setlocale(LC_ALL, "en_US.utf8");
把UTF8存储的std::string转换为std::wstring可以使用标准库的 std::mbstowcs() 和 std::wcstombs() 函数,具体可以参考标准库转换函数。
Java
Java中的char是双字节,只能表达UTF16中的BMP部分字符。
BMP:U+0000~U+D7FF, U+E000~U+FFFF
【注】有人实验说char内部编码为UTF16,和 Charset.defaultCharset() 没有关系。
如果想遍历出String里所有中英文字符,一般简单来说调用 String.toCharArray() 遍历char数组即可,风险是BMP外的Unicode字符会出错。
Python
如果已知字符的unicode编码但不清楚字符,或者想输出某已知字符的unicode编码,可以借助python预览一下。先确定你终端的locale是en_US.UTF-8等unicode兼容环境。
>>> print u"\u4e00"
一
>>> "一".decode("utf8")
u'\u4e00'
>>> hex(ord(u'\u4e00'))
'0x4e00'