字符编码 | Python

1,636 阅读5分钟

人类使用文本,计算机使用字节序列

Python3字符编码

Python3的字符串类型是str,在内存中以Unicode表示,一个字符对应若干个字节。如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes。在将字节转为字符的时候,如果编码方式不对,就会出现乱码。

Python对bytes类型的数据用带b前缀的单引号或双引号表示(b'123'),使用的编码为ASCII,所以不能存储中文

编码解码过程:

Unicode三明治--目前处理文本的最佳实践

Unicode三明治

bytes ---decode()--> str(Unicode) ---encode()---> bytes

Python3的字符串与字节

类型 编码 示例
字符串 str Unicode "123中"
字节 bytes ASCII b"123"

Python3字符串中的u,b,r前缀

字符串前缀 编码方式 作用 示例
u或无前缀 Unicode 表示字符串 u"123""123"
b ASCII 表示字节 b"123"
r Unicode 清除转义,所有字符都为普通字符 r"F:/Python"

ASCII、Unicode和UTF-8区别

编码方式是一种规则,与编程语言无关,在Python、Java和SQL中都是一样的。

编码 字节 字符 目的 使用场景
ASCII 1 英文字母、数字、符号
Unicode 2+ 所有字符 统一标准,解决乱码 计算机内存
UTF-8 1-6 所有字符 减少编码长度,方便传输、存储 存储、传输

Unicode 字符编码标准是固定长度的字符编码方案,它包含了世界上几乎所有现用语言的字符。在最初的版本中,两个字节的Unicode最多只能表示65535个字符,所以之后的版本对Unicode有扩充。

UTF-8又称为可变长编码,是Unicode 的实现方式。

为什么中文在UTF-8里需要占用3个字节,在Unicode中占用2个字节?

也就是说,UTF-8的目的是减少编码长度,那只会比Unicode短,为什么还会比它长呢?

这是由于UTF-8的编码规则决定的,由于utf-8规则天然占用字节前几位,若与Unicode同样用2字节16位表示一个中文字符,则utf-8除去规则占用,只剩余16-5=11位,无法表示Unicode下的两个字节(16位)所表示的字符。所以UTF-8使用了3个字节。

另外,UTF-8中英文字符占用一个字节;绝大多数汉字(基本汉字)占用三个字节,个别汉字占用四个字节。

UTF-8 编码规则

  1. 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的,即UTF-8编码能够兼容ASCII。
  2. 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

下表总结了编码规则,字母x表示可用编码的位。

Unicode编码 UTF-8编码 解释
(十六进制) (二进制) Unicode部分为16进制编码, UTF-8编码为2进制
0000 0000-0000 007F 0xxxxxxx UTF-8规定,若1字符=1字节,首位须为‘0’
0000 0080-0000 07FF 110xxxxx 10xxxxxx UTF-8规定,若1字符=2字节,高位字节前3位为‘110’,低位前2位为‘10’
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx UTF-8规定,若1字符=3字节,高位字节前3位为‘110’,后面低位前2位一律为‘10’(占4,5字节字符规则以此类推)

Java中的字符编码

要分清内码(internal encoding)和外码(external encoding)。

  1. 内码 :某种语言运行时,其char和string在内存中的编码方式。
  2. 外码 :除了内码,皆是外码。源代码编译产生的目标代码文件(可执行文件或class文件)中的编码方式属于外码。

Java中的字符编码

  1. java中内码(运行内存)中的char使用UTF16的方式编码,一个char占用两个字节,但是某些字符需要两个char来表示。所以,一个字符会占用2个或4个字节。
  2. java中外码中char使用UTF8的方式编码,一个字符占用1~6个字节。
  3. UTF16编码中,英文字符占两个字节;绝大多数汉字(尤其是常用汉字)占用两个字节,个别汉字(在后期加入unicode编码的汉字,一般是极少用到的生僻字)占用四个字节。

String.getBytes()是一个用于将String的内码转换为指定的外码的方法。无参数版使用平台的默认编码作为外码,有参数版使用参数指定的编码作为外码;将String的内容用外码编码好,结果放在一个新byte[]返回。

引用

  1. 字符串和编码-廖雪峰
  2. Python3字符串前缀u、b、r
  3. 在UTF-8中,一个汉字为什么需要三个字节?
  4. ASCII,Unicode和UTF-8终于找到一个能完全搞清楚的文章了
  5. Java中char占用几个字节
  6. Java 语言中一个字符占几个字节?