字符串和编码
大家有没有遇到过复制粘贴代码出乱码、打开老中文txt全是方框的崩溃时刻?90%的这类问题,源头都是没搞懂「字符串和编码」!今天就从底层逻辑到Python实操,一口气讲明白👇
1. 字符编码基础
1.1 为什么要有编码?
先想清楚计算机的本质:它是只认二进制0和1的机器!哪怕是我们随手敲的“Hi 中文😊”,也得先转成一串数字(再转成二进制),才能在内存、磁盘、网络里跑。
而计算机最早诞生在美国,设计时用8个比特(bit,最小存储单位)凑成1个字节(byte,最常用的可寻址单位)——单字节最多能表示0-255共256个数字,完全够英文日常用。
1.2 ASCII:第一个通用但“排外”的标准
1967年发布的ASCII(美国信息交换标准代码),直接解决了“英文转数字”的问题:
- 用0-127这128个数字,对应英文字母大小写、阿拉伯数字、标点符号、回车换行这些控制字符
- 比如大写A=65,小写z=122,空格=32
但它的局限性也很明显:完全没考虑中文、日文、韩文这些非拉丁语系的文字。
1.3 多语言混战:乱码的根源
为了让自己的语言能被计算机显示,各国开始自己搞编码标准:
- 中国用GB2312(简化字,2字节存一个字),后来升级到GBK(兼容GB2312,还加了繁体字)、GB18030
- 日本用Shift_JIS
- 韩国用Euc-kr
麻烦的是:不同标准的同一段数字,对应完全不同的文字!比如同样的二进制存起来,在GBK里是“你好”,在Shift_JIS里可能就变成乱码了——这就是我们常说的“乱码困境”。
1.4 Unicode:一统江湖的“通用字符集”
直到1991年Unicode联盟发布Unicode标准,这个问题才算找到终极解决方案:
- 它给全球每一个文字、符号(甚至表情😊)都分配了唯一的“身份证号”,叫码点(Code Point)
- 最常用的是UTF-16(日常文字2字节,生僻字/表情4字节),现代操作系统、编程语言的底层基本都用Unicode或其变种存内存
1.5 UTF-8:存储/传输的“性价比之王”
但UTF-16有个小缺点:哪怕是ASCII里的单个英文字母,也要占2字节,对于英文为主的文本,空间浪费了一半!
于是UTF-8(Unicode Transformation Format 8-bit)诞生了,它是Unicode的可变长编码实现,完美平衡了兼容性和存储效率:
- 英文字母/ASCII字符:1字节(和ASCII完全一样,所以ASCII文件直接用UTF-8打开也没问题)
- 常用汉字/日文假名:3字节
- 生僻字符/表情:4-6字节
现在,全球99%的网页、软件、文件都默认用UTF-8!
2. 实际工作中的编码流程
记住这个核心原则:「内存用Unicode,存储/传输转UTF-8」
- 打开文本、输入文字时:系统自动把UTF-8转成Unicode,存在内存里供你编辑
- 保存文件、发送消息时:再把Unicode转回UTF-8,存到磁盘或通过网络传输出去
比如网页里的<meta charset="UTF-8">,就是告诉浏览器:“请用UTF-8来解码这段内容哦!”
3. Python字符串处理(Python 3专属)
Python 3对字符串和编码做了彻底的优化:默认字符串就是Unicode,完全解决了Python 2里的str/unicode混用坑!
3.1 基础支持多语言
直接写就行,不用加任何前缀或转义:
3.2 字符与Unicode码点的互转
ord(字符):获取单个字符的十进制Unicode码点chr(码点):把十进制码点转回单个字符
3.3 Unicode码点的十六进制写法
如果不想用chr(),也可以直接在字符串里写\u加4位十六进制,或\U加8位十六进制(生僻字/表情用):
3.4 bytes类型:专门存二进制数据
网络传输、磁盘读写都不能直接传Unicode字符串,必须转成二进制流(bytes类型):
- bytes用
b前缀表示,每个元素是0-255的整数,显示时会把可打印的ASCII字符直接打出来,不可打印的用\x加两位十六进制表示
3.5 str与bytes的核心转换方法
str.encode(编码方式):Unicode字符串 → bytes(编码)bytes.decode(编码方式):bytes → Unicode字符串(解码)
默认都用UTF-8,但最好显式指定,避免跨环境出问题:
3.6 解码错误的优雅处理
如果遇到部分损坏的二进制数据,直接用默认的strict模式会报错,可以用errors参数处理:
3.7 长度计算要注意区分类型
len(str):计算字符数len(bytes):计算字节数
3.8 Python源代码的编码规范
如果你的Python文件里有中文、日文等非ASCII字符,必须做两件事:
- 把文件保存为UTF-8格式(现代编辑器默认都是,但最好确认一下)
- 在文件最开头加编码声明(虽然Python 3默认会尝试用UTF-8,但显式声明更规范)
4. Python字符串格式化(3种主流方式)
4.1 %格式化:传统但兼容性强
这是Python 1就有的方式,用%s(字符串)、%d(整数)、%f(浮点数)等占位符:
4.2 format()方法:Python 2.7/3.0引入
用{}占位符,支持按位置、按名字传参,更灵活:
4.3 f-string:Python 3.6+推荐!(最简洁最快)
直接在字符串前加f,占位符里写变量名或表达式,还支持各种格式化:
5. 避坑最佳实践
- 默认全用UTF-8:不管是文本文件、代码保存、网络接口、数据库,能选UTF-8就选UTF-8
- 优先用f-string:Python 3.6+环境下,它是最简洁、可读性最高、性能最好的格式化方式
- 处理文件I/O必须显式指定编码:不要依赖系统默认编码(Windows默认GBK,Mac/Linux默认UTF-8,容易出乱码)
- Python 3里千万别混用str和bytes:两者不能直接拼接、比较,必须显式转换
6. 小练习
用Python 3的f-string计算小明的成绩提升率:
7. 总结
- 计算机只能认二进制,所以文本必须转成编码(数字→二进制)
- Unicode是「通用字符身份证」,内存里都用它;UTF-8是「性价比传输编码」,存储/传输用它
- Python 3的str默认是Unicode,完美解决多语言问题;bytes专门存二进制
- 字符串格式化优先用Python 3.6+的f-string
- 始终显式指定UTF-8,避免跨环境乱码!

