编码方式
- 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'