UTF-8 编码格式

UTF-8格式是一种编码格式.确切的说,它是一种存放Unicode的容器.Unicode包含几乎所有我们需要用到的字符,为了包含这么多内容Unicode本身是一个长整型.但具体存放的时候,我们需要将Unicode拆成若干个Byte.而如何将Unicode序列化呢?UTF-8就是一种解决方案.

UTF-8标准可以参考RFC3629.长话短说,就是将Unicode的高位的0去掉,得到长短不等的Unicode信息,然后在每个Byte高位写入序列信息.因为ABCD等ASCII字符更加常用,而很多Unicode值比较大的并不是很常用,更重要的是,当我们只是用ASCII范围内的数据的时候,UTF-8和ASCII是兼容的,简直美妙.

RFC3629规定每个字节存储如下:

Char. number range (hexadecimal) | UTF-8 octet sequence (binary)
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

单字节在最高位为0,之后7个字节存放内容. 超过1个字节的,在最高位补字节个数个1,再加上10(也即是说,用字节长度个+2个bit作为信息位).从第二个字节开始最高的两位为10.因为这种特性,UTF-8最高可以有6位.(再多就没有坑啦).

知道了规律,那么我们面对一个UTF-8的字符串,切字就很方便了.首先检查字符串长度,然后从当前位开始切长度个过去.我写了个demo 在此处,各位有兴趣可以参考下.

调用也很简单

#include
#include

#include "argcv/cxx/str/str_helper.h"

using std::string;
using std::vector;

using namespace argcv;

int main(int argc, char* argv[]) {
vector elems = Utf8Split("abcd\u00A0你好世界123\n");
for (size_t i = 0; i < elems.size(); i++) {
printf("%zu (%s):%lu\n", i,
elems[i].c_str(), elems[i].length());
}
return 0;
}

输出结果如下:

$ ./run_example
0 (a):1
1 (b):1
2 (c):1
3 (d):1
4 ( ):2
5 (你):3
6 (好):3
7 (世):3
8 (界):3
9 (1):1
10 (2):1
11 (3):1
12 (
):1