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 <string> #include <vector> #include "argcv/cxx/str/str_helper.h" using std::string; using std::vector; using namespace argcv; int main(int argc, char* argv[]) { vector<string> 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
7 Comments
Yuan · July 30, 2015 at 19:26
orz
mooc · July 8, 2015 at 17:22
用模板来实现,好高级。。
yu · July 8, 2015 at 23:07
@mooc huh? 但是我这段代码并没有用模板啊
mooc · July 8, 2015 at 23:16
@yu QAQ弄错了,是vector。。不过vector容器也算模版吧
yu · July 8, 2015 at 23:25
@mooc 是, 不过不是我写的模板.
某感知机我倒是的确用模板来写的,可惜太水了没人看 ….
另,刚去你那儿看了下,高三的孩子啊,好厉害的说.
mooc · July 8, 2015 at 23:29
@yu 哎,差你一大截,我还得多跟前辈学习呢:) 你的文章除了编程以外我一篇都看不懂
yu · July 8, 2015 at 23:36
@mooc 按你高三算,我比你虚长上六七岁呢.
何况,我所说的,在我在的比较细的专业上其实也都是很多年前的论文里已经讲烂的浅显的知识.只是术业有专攻,看起来比较猎奇罢了.
他日你在别的领域上学点什么,我去看你博客,大约也完全看不懂了吧.