比特 bit 字节 byte ASCII码 Unicode UTF 32 UTF 8 傻傻分不清楚
"1个字节是8个比特,1个字母是1个字节,1个汉字是2个字节"
- 上面这句话很多人都看过听过
- 但大部分人都不知道为什么 (例如前两天的我)
- 这句话在某些规定下其实是不正确的
bit
- 中文:比特
- 表示0或1
- 计算机中最小的单位
byte
- 中文:字节
- 1byte==8bit 表示8个比特(为什么不是2个或者4个 后面解答)
插一句 比特币 字节跳动 名字取的真好
ASCII码
- 美国制定的一套让计算机识别、保存、读取字符的标准
- 字符定义: 数字'7' 字母'a' 操作字符(删除 确定)
- 一共有128个字符 每个字符都有唯一的编码 查看ascii.pdf
- 计算机中最小的单位是比特所以我们用比特来存储
- 那么需要多少个比特来存一个字符呢?
- 2比特 最多保存 4个数据 00 01 10 11
- 4比特 最多保存16个数据 0000 0001 0010 0011 ...... 1111
- 7比特 最多保存128个数据 0000000 0000001 0000010 0000011 ...... 1111111
- 8比特 最多保存255个数据 00000000 00000001 00000010 00000011 ...... 11111111
- 其实7bit就可以保存128个字符 但是最后还是用8比特 因为当时用第八位来作为奇偶校验位(奇偶校验位现在没用)
- byte的概念最早是用来表示一个"字" 也就是char 最后通俗约定 8bit表示1byte
- 例外:GSM默认采用7bit编码
GB2312编码 GBK编码 GB18030编码 XXXX编码
- 如果全世界都用英语那ASCII码也够用了
- 但中国 日本 韩国 也想用计算机显示自己国家的文字
- 所以中国制定了GB2312 日文制定了Shift_JIS 韩文制定了EUC_KR
- 每个国家都制定了自己的编码 一般都用2~4字节来表示一个文字
Unicode字符集
- 每个国家的编码不一样导致很容易产生乱码
- 如何让所以国家都用一个表来确定字符的编号(学名为码位 / 码点 / Code Point)
- Unicode就孕育出生了(统一码、万国码、单一码)
- Unicode准备了1114112个编号来存放世界上所有的文字
- 1114112 二进制为 10001 00000000 00000000 20bit
- 2020年3月10日发布了最新的Unicode®13.0.0.pdf
UTF-32 (或 UCS-4)编码
- 规定每个字符都以4byte(32bit)去存储 读取 传输
- 优点
- 快速获取字符数量
- 快速获取数据中的指定字符
- 缺点
- 本来1byte(4bit)就能保存的数据都需要用4byte(32bit) 来保存很浪费容量
- 存储 读取 传输慢
UTF-8编码
-
使用1~4个byte确定一个字符
-
UTF-8编码划分Unicode字符集为四个区间
十进制 | 二进制 |
---|---|
0-177 | (00000000 00000000 00000000 00000000)-(00000000 00000000 00000000 01111111) |
178-2047 | (00000000 00000000 00000000 11111111)-(00000000 00000000 01111111 11111111) |
2048-65535 | (00000000 00000000 11111111 11111111)-(00000000 01111111 11111111 11111111) |
65536-1114111 | (00000000 11111111 11111111 11111111)-(01111111 11111111 11111111 11111111) |
- 四个区间分别对应四个公式
公式 |
---|
0xxxxxx |
110xxxxx 10xxxxxx |
1110xxxx 10xxxxxx 10xxxxxx |
11110xxx 10xxxxxx 10xxxxxx |
- 例如
字符 | 十进制 | 二进制 | 属于区间 |
---|---|---|---|
z | 122 | 01111010 | 1 |
邹 | 37049 | 10010000 10111001 | 3 |
- 字符 'z' 属于第一区间 套用第一个公式
- 使用 'z' 的二进制 01111010 从右到左依次填入0xxxxxx
- 最终得 'z' 的 UTF-8码 为 01111010
- 字符 '邹' 属于第三区间 套用第三个公式
- 使用 '邹' 的二进制 10010000 10111001 从右到左依次填入 1110xxxx 10xxxxxx 10xxxxxx
- 最终得 '邹' 得 UTF-8码 为 11101001 10000010 10111001
- 优点
- 兼容ASCII码
- 保存 读取 传输 低于178范围的字符只需要一个byte(4bit)
- 根据字符的二进制前有多少个1可以确定一个字符的长度
- 缺点
- 不能直接获取数据包含多少个字符
- 不能直接定位某个字符的二进制位置
总结
- 1个汉字是2个字节 在UTF-8编码规则下错误的
- 以上都是个人见解
- 如有错漏之处敬请指正
Github:https://github.com/QiangZou