UTF-8学习笔记贴
UTF-8 学习笔记(C++)
学习原因
虽然从事多年编程,之前一直在国外项目,近一年接收国内项目,对中文的支持成为必要的需求,之前遇到乱码的问题,都是网上找解决方案,没有从根本上理解这个事情,抽出时间理解一下相关底层的处理逻辑,相关知识点在此处记录。
什么是 UTF-8
摘录自百度百科:https://baike.baidu.com/item/UTF-8/481798?fromtitle=UTF8&fromid=772139&fr=aladdin
UTF-8(8 位元,Universal Character Set/Unicode Transformation Format)是针对 Unicode 的一种可变长度字符编码。它可以用来表示 Unicode 标准中的任何字符,而且其编码中的第一个字节仍与 ASCII 相容,使得原来处理 ASCII 字符的软件无须或只进行少部份修改后,便可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。
摘要自*:https://zh.wikipedia.org/wiki/UTF-8
UTF-8(8-bit Unicode Transformation Format)是一种针对 Unicode 的可变长度字符编码,也是一种前缀码。它可以用一至四个字节对 Unicode 字符集中的所有有效编码点进行编码,属于 Unicode 标准的一部分,最初由肯·汤普逊和罗布·派克提出。由于较小值的编码点一般使用频率较高,直接使用 Unicode 编码效率低下,大量浪费内存空间。UTF-8 就是为了解决向后兼容 ASCII 码而设计,Unicode 中前 128 个字符,使用与 ASCII 码相同的二进制值的单个字节进行编码,而且字面与 ASCII 码的字面一一对应,这使得原来处理 ASCII 字符的软件无须或只须做少部分修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或发送文字优先采用的编码方式。
划重点:
- 第一个字节 ASCII 相容
- 处理 ASCII 字符的软件无须或只进行少部份修改后,便可继续使用
引出问题:
- 第一个字节兼容,那么后面的字节怎么处理
- ASCII 字符串软件如何修改可以继续使用(可能和上个问题是同一个问题)
UTF-8 占几个字节
摘录自百度百科:https://baike.baidu.com/item/UTF-8/481798?fromtitle=UTF8&fromid=772139&fr=aladdin
UCS 字符 U+0000 到 U+007F(ASCII)被编码为字节 0×00 到 0x7F(ASCIⅡ 兼容)。这意味着只包含 7 位 ASCIl 字符的文件在 ASCIⅡ 和 UTF-8 两种编码方式下是一样的。
所有大于 0x007F 的 UCS 字符被编码为一个有多个字节的串,每个字节都有标记位集。因此,ASCIl 字节(0x00-0x7F)不可能作为任何其他字符的一部分。表示非 ASCIl 字符的多字节串的第一个字节总是在 0xC0 到 0XFD 的范围里,并指出这个字符包含多少个字节。多字节串的其余字节都在 0x80 到 0xBF 范围里。这使得重新同步非常容易,并使编码无国界,且很少受丢失字节的影响。
UTF-8 编码字符理论上可以最多到 6 个字节长,然而 16 位 BMP 字符最多只用到 3 字节长,Bigendian UCS-4 字节串的排列顺序是预定的,字节 0xFE 和 OxFF 在 UTF-8 编码中从未用到
摘要自*:https://zh.wikipedia.org/wiki/UTF-8
UTF-8 使用一至六个字节为每个字符编码(尽管如此,2003 年 11 月 UTF-8 被 RFC 3629 重新规范,只能使用原来 Unicode 定义的区域,U+0000 到 U+10FFFF,也就是说最多四个字节):
128 个 US-ASCII 字符只需一个字节编码(Unicode 范围由 U+0000 至 U+007F)。
带有附加符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母则需要两个字节编码(Unicode 范围由 U+0080 至 U+07FF)。
其他基本多文种平面(BMP)中的字符(这包含了大部分常用字,如大部分的汉字)使用三个字节编码(Unicode 范围由 U+0800 至 U+FFFF)。
其他极少使用的 Unicode 辅助平面的字符使用四至六字节编码(Unicode 范围由 U+10000 至 U+1FFFFF 使用四字节,Unicode 范围由 U+200000 至 U+3FFFFFF 使用五字节,Unicode 范围由 U+4000000 至 U+7FFFFFFF 使用六字节)。
对上述提及的第四种字符而言,UTF-8 使用四至六个字节来编码似乎太耗费资源了。但 UTF-8 对所有常用的字符都可以用三个字节表示,而且它的另一种选择,UTF-16 编码,对前述的第四种字符同样需要四个字节来编码,所以要决定 UTF-8 或 UTF-16 哪种编码比较有效率,还要视所使用的字符的分布范围而定。不过,如果使用一些传统的压缩系统,比如 DEFLATE,则这些不同编码系统间的的差异就变得微不足道了。若顾及传统压缩算法在压缩较短文字上的效果不大,可以考虑使用 Unicode 标准压缩格式(SCSU)。
划重点:
- 第一个字节中 [ 0x00 - 0x7F ] (ASCII 兼容)最高位
- 第一个字节标记了整个数的字节数,
0b0zzzzzzz 表示由1个字节组成的字符,剩余7位用户表示字符值(即单字节ASCII码)
0b110yyyyy 表示由2个字节组成的字符,剩余6位用户表示字符值
0b1110xxxx 表示由3个字节组成的字符,剩余5位用户表示字符值
0b11110www 表示由4个字节组成的字符,剩余4位用户表示字符值
首字节 | 首字节值区间 | 字节数 |
---|---|---|
0b0zzzzzzz |
0x00~0x7F < 0x8F |
1 |
0b110yyyyy |
0x8F~0xDF < 0xE0 |
2 |
0b1110xxxx |
0xE0~0xEF < 0xF0 |
3 |
0b11110www |
0xF0~0xF7 < 0xF8 |
4 |
UTF-8 字符值
字节数 | 字节 1 | 字节 2 | 字节 3 | 字节 4 | 有效字符值位数 | 字符值 | 字符值区间 |
---|---|---|---|---|---|---|---|
1 | 0b0zzzzzzz |
- | - | - | 7 = 7 |
0bzzzzzzz |
0x00~0x7F < 0x8F |
2 | 0b110yyyyy |
0b10zzzzzz |
- | - | 5 + 6 = 11 |
0byyyyyzzzzzz |
0x8F~0x7FF < 0x800 |
3 | 0b1110xxxx |
0b10yyyyyy |
0b10zzzzzz |
- | 4 + 6 + 6 = 16 |
0bxxxxyyyyyyzzzzzz |
0x800~0xFFFF < 0x10000 |
4 | 0b11110www |
0b10xxxxxx |
0b10yyyyyy |
0b10zzzzzz |
3 + 6 + 6 + 6 = 21 |
0bwwwxxxxxxyyyyyyzzzzzz |
0x10000~0x1FFFFF < 0x200000 |