C++截取定长utf8字符及字符集与字符编码总结

之前有个需求要求从一段utf8编码的文字中截取前n个字符,由于文字中包含既有中文又有数字字母等,这些字符所占的字节数都不相同,所以直接截取前M个字符可能会导致乱码问题。在完成截取之前,需要先了解utf8编码字符的存储规则。后面简单介绍一下常见的字符集及字符编码

utf8编码规则

在理解utf8编码规则之前先说一下utf16和utf32的编码规则,utf32规定所有的unicode字符集上的所有字符都是用32bit来存储,即可存储的字符数可达2^32个,接近40亿,这明显可以容纳已有的所有字符。utf16编码使用2个字节存储,超过此范围的使用其他特殊技巧处理。使用utf16和utf32有一个问题,就是会受到计算机存储大端规则和小端规则的影响。所以utf16又有utf16_LE和utf16_BE之分。为了解决这个问题,需要在文本文件的开头定义一个BOM(Byte order Mark),这是一个非打印标志,用此标志来标志当前文本存储是大端存储还是小端存储。

utf8是一种针对unicode的可变长度字符编码,也是一种前缀码,它可以表示unicode标准中的任何字符。且与ascii码兼容,这使得我们处理ascii字符的时候不许做特殊修改。

utf8使用1~6个字符为每个字符编码,但实际使用中只使用了4个。

utf8编码规则:

(1)对于单字节字符,字节的第一位为0,后面7位为这个字符的unicode码,因此对于ascii码,unicode与ascii保持一致。
(2)对于n字节符号(n>1),第一个字节的前n位都为1,第n+1位为0,其他字节的前两位都为10,其余位为实际的unicode位。

规则:

unicode范围 二进制表示范围
U-00000000 - U-0000007F 0xxxxxxx
U-00000080 - U-000007FF 110xxxxx 10xxxxxx
U-00000800 - U-0000FFFF 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 - U-001FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 - U-03FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 - U-7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

利用上述utf8编码规则实现C++截取定长字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const string utf8Cut(const string &src, int utf8Len) {
string ret;
int utf8LenCnt = 0;
int srcIdx = 0;
int srcLen = src.length();
int cutLen = 0;
unsigned char tmp;
while (utf8LenCnt < utf8Len && srcIdx < srcLen) {
tmp = (unsigned char)src[srcIdx];
if (tmp >= 252)
cutLen = 6;
else if (tmp >= 248)
cutLen = 5;
else if (tmp >= 240)
cutLen = 4;
else if (tmp >= 224)
cutLen = 3;
else if (tmp >= 192)
cutLen = 2;
else if (tmp >= 65 && tmp <=90)
cutLen = 1;
else
cutLen = 1;
ret += src.substr(srcIdx, cutLen);
srcIdx += cutLen;
++utf8LenCnt;
}
return ret;
}

字符集与字符编码

字符集是一个系统所支持的字符的集合,常见的字符集包括ascii字符集,GB2312字符集,GBK字符集以及unicode字符集。其中ascii字符集包括所有的英文字母数字以及控制字符等等。

字符编码是用来定义计算机中某个字符的存储和传输规则。

区别:字符集仅仅是一个字符集合,与计算机的存储和传输没有关系,而字符编码规定了计算机中字符的编码规则。

常见的字符集及字符编码

  • ascii字符集及字符编码:使用一个字符编码,包括所有的字母数字,换行以及控制字符等。
  • GB*字符集及编码:是一种多字节编码标准,GB表示国标,包括GB2312,GBK等编码,2312是标准号,GB2312涵盖了绝大多数的中文,但是一些生僻字不包含在其中,GBK是对GB2312的扩展.
  • BIG*:常见的为BIG5字符集及编码,BIG5中收录了大部分的中文繁体,常用语香港台湾等地区。
  • unicode字符集及编码:unicode又称为统一码,几乎涵盖了所有国家和地区的所有字符,并还在不断的扩充新字符。unicode是一个字符集,而不是编码规则,我们常见的utf8,utf16以及utf32是unicode常见的字符编码.