一个字节真能存 255 个字符吗?聊聊字节和字符
字节和字符是两个特别容易混的概念。
很多人写代码处理文本,碰到乱码、截断、长度算错,根子上都在这。
说白了,搞清楚字节、字符、编码这三者的关系,大部分文本处理的坑就能绕开。
字节是什么?
字节(byte)是计算机存储和传输数据的基本计量单位。
一个字节由 8 个比特(bit)组成。
每个比特只有 0 和 1 两种状态,所以一个字节能表示 2^8 = 256 种不同的状态,对应 0 到 255 这 256 个整数。
注意这里的措辞:是「表示 256 种状态」,不是「存 256 个字符」。
字节本身不关心你存的是字符、数字还是图片像素,它只是一串二进制位。
字符是什么?
字符(character)是文字、字母、数字和各种符号的统称。
比如汉字「中」、字母 A、数字 7、标点 ?,甚至空格和换行,都算字符。
字符是给人看的,字节是给机器存的。
两者中间隔着一层东西,叫编码。
字符和字节靠什么连起来?
靠字符编码。
编码规定了「某个字符」对应「哪一串字节」。
输入文本时,把字符转成字节序列,这个过程叫编码(encode)。
输出文本时,把字节序列还原成字符,这个过程叫解码(decode)。
编码和解码用的规则必须一致,否则就乱码。
最常见的乱码场景,就是 UTF-8 编码的内容拿 GBK 去解码,一堆「锟斤拷」就是这么来的。
一个字节能存多少字符?看编码
不同编码下,一个字符占的字节数完全不一样。
下面这张表直接对比:
| 编码方式 | 一个字符占用字节 | 说明 |
|---|---|---|
| ASCII | 1 字节 | 只覆盖 128 个字符,英文够用 |
| Latin-1 | 1 字节 | 西欧语言,扩展到 256 个字符 |
| GBK | 1~2 字节 | 中文常用 2 字节 |
| UTF-8 | 1~4 字节 | 变长编码,最通用 |
| UTF-16 | 2 或 4 字节 | 常用字符 2 字节 |
| UTF-32 | 固定 4 字节 | 不省空间但定位快 |
所以「一个字节能存多少字符」这个问题,离开编码就没法回答。
ASCII:一个字节存一个字符
ASCII 是最早的字符编码,1967 年定稿。
它只用了一个字节里的低 7 位,能表示 128 个字符(0 到 127)。
包括大小写英文字母、数字、常见标点和一些控制字符。
最高位那一位空着没用,所以一个 ASCII 字符正好用一个字节存。
这也是「一个字节存一个字符」这种说法的来源。
但它只对英文成立。
UTF-8:变长,中文通常 3 字节
UTF-8 是目前互联网上用得最多的编码。
它最大的特点是变长:不同字符占的字节数不一样。
- ASCII 范围内的字符(英文、数字)仍然只占 1 字节,完全兼容 ASCII
- 拉丁文带音标、希腊文、西里尔文等占 2 字节
- 绝大多数常用汉字占 3 字节
- emoji、生僻字、部分扩展汉字占 4 字节
这里得纠正一个常见的误区:不是「所有中文都占 3 字节」。
基本多文种平面(BMP)内的常用汉字确实是 3 字节,但像「𠮷」这种扩展区汉字,是 4 字节。
emoji 比如「😀」也是 4 字节,有时候渲染上去还是好几个码点拼的,算下来更多。
那「一个字节最多存 255 个字符」对吗?
不对,这是个典型的错误说法。
它把「一个字节能表示 256 种状态」和「能存多少字符」混为一谈了。
256 种状态指的是这个字节能取多少种不同的值,不是能装下多少个字符。
一个字节就是一个字节,它顶多完整存下一个 ASCII 字符。
碰上 UTF-8 的中文,一个字节连半个字都存不下,得三个字节凑一块儿才行。
所以结论很清楚:一个字符要占几个字节,取决于编码;而一个字节能不能存下一个字符,同样取决于编码。
常见问题
Q1. 字节和字符到底有什么区别?
字节是机器存储数据的单位,固定 8 位,能表示 256 种状态。
字符是人能看懂的文字符号。
两者通过字符编码互相转换,一个字符可能占一个或多个字节。
Q2. 为什么一个汉字在 UTF-8 里是 3 个字节?
UTF-8 是变长编码,按字符的 Unicode 码点范围分配字节数。
绝大多数常用汉字的码点落在需要 3 字节表示的区间里。
但生僻字和扩展区汉字会占 4 字节,并非全部都是 3 字节。
Q3. 字符串长度算的是字节还是字符?
看编程语言和方法。
有的语言 len() 算字节数(比如 Go 对字符串直接取长度),有的算字符数(Unicode 码点)。
处理多字节文本时分不清这点,很容易把中文长度算错或者截断出半个字。
Q4. 乱码是怎么产生的?
编码和解码用的规则不一致就会乱码。
比如用 UTF-8 存的文件,拿 GBK 去打开,字节序列被错误地拆分还原,就显示成一堆怪符号。
统一编码(尽量都用 UTF-8)是避免乱码最省事的办法。
小结
字节管存储,字符管表意,编码是它们之间的翻译规则。
「一个字节存一个字符」只在 ASCII 下成立,「一个字节最多存 255 个字符」则纯属误解。
真要回答「一个字节能存几个字符」,先问一句:用的什么编码?
如果你在项目里还碰到过更刁钻的编码坑,比如 BOM 头、UTF-16 大小端之类的,欢迎在评论区聊聊~~~
版权声明
未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!
本文原文链接: https://fiveyoboy.com/articles/byte-and-character/
备用原文链接: https://blog.fiveyoboy.com/articles/byte-and-character/