字符串编码可以说新手必碰壁,我以前看了很多文章还是感觉朦朦胧胧,所以这篇文章我从字符串存储开始介绍字符串编码的实现,希望可以帮到各位。一文理解字符串编码
1
jingniao 2018-04-19 08:38:50 +08:00
其实弄清楚
字节 字符 编码 解码 之间的关系,应该好理解好多。 然后对于各个语言,对字符串,到底是默认 unicode 还是 bytes |
2
faemon 2018-04-19 08:48:31 +08:00 via iPhone
新手弄不清楚的话的确很懵,这篇文章挺好的
|
3
sundev 2018-04-19 10:19:25 +08:00
现在基本都是 utf8 一统江湖了吧。
但是有时候真出现乱码问题,真要解决必须得懂得这些知识,还要熟知各个环节(语言、服务、数据库、文件等)获取到的数据的编码是什么,对能力是很大的考验。 |
4
mortonnex 2018-04-19 10:30:03 +08:00
牛!
|
5
di94sh 2018-04-19 11:14:39 +08:00 via Android
其实很简单的逻辑,字符组成字符集,比如 gbk unicode 等等字符集。然后现在世界上个语言字符收录最全的,应用最广的是 Unicode 字符集。然后实现一个字符集有很多种编码方式,utf-8 utf-16 等等 都是一些实现 unicode 字符集的编码方式 二进制 转到 Unicode
然后在编码里 你要明白你写的语言的字面到底是二进制,还是 Unicode 比如 python python2 字符串字面上是二进制的 然后你如果转成 Unicode 的 python2 的默认转码方式是 assic 只支持英文,数字,标点,等字符。 所以在处理非英语的时候会出错误,你在转吗的时候指定 utf-8 就好了。 python3 字符串字面上是 Unicode 的 然后 python3 的默认编码方式是 utf-8,所以你转吗的时候可以使用默认编码 最后 二进制 → Unicode 用 decode 解码 Unicode → 二进制 用 encode 编码 |
6
hxndg 2018-04-19 13:40:15 +08:00
很不错的文章,提几点建议:
1去掉那几张巨大而且不相关的图片。 2加上不同语言中对于字符的默认处理和转换,比方说 python2.7, python3, ruby 等。 3提及计算机大端小端和网络上的大端小端。 |
8
Windsooon OP @hxndg 谢谢,第一点我会换小一点图片的,哈哈,第二点我会在常用问题增加的,第三点的话我不确定需不需要添加,我怕会让读者更加困惑。
|
9
Sylv 2018-05-12 06:16:22 +08:00
文章很不错。
不过挑几个 Python 2 相关的错,或者说是表述不准确的地方: 1-- 「 python2 是把字符串直接经过 utf-8 编码保存的」 「出错的原因是因为 python2 当遇到 ASCII 表中没有的字符的时候,默认会把它们使用 utf-8 编码来存储」 其实并不是这样的,Python 2 并没有默认用 utf-8 编码来保存字符串,实际上在终端下输入的字符串的编码是由终端的编码决定的,也就是说终端用的是什么编码,Python 接收到的字符串就是什么编码。你这句话最多只能适用于 Mac 和大多数 Linux 系统等,因为它们终端的默认编码是 utf-8,所以在终端下输入 "你好",Python 接收到的是 utf-8 编码的 '\xe4\xbd\xa0\xe5\xa5\xbd'。但是在 Windows 下就不是这样了: >>> '你好' '\xc4\xe3\xba\xc3' 结果并不是 utf-8 编码的 '\xe4\xbd\xa0\xe5\xa5\xbd'。这是因为中文 Windows 系统 cmd 的默认编码是 cp936 (GBK),而不是 utf-8。可以通过 sys.stdin.encoding 来查看这个编码: >>> import sys >>> sys.stdin.encoding 'cp936' 所以在这种情况下输入 "你好",Python 接收到的二进制数据会是 '\xc4\xe3\xba\xc3',也就是 "你好" 的 cp936 编码: >>> u'你好'.encode('cp936') '\xc4\xe3\xba\xc3' 这个道理和 Python 读取文件内字符串是一样的,文件是什么编码,Python 读取到的字符串就是什么编码。Python 2 并没有默认使用 utf-8 编码来保存或读取字符串,而是由输入端(文件、终端等)的编码决定了 Python 2 获取到的字符串的编码。 2-- 「 >>> '你好'.encode('gb2312') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128) 出错的原因是因为 python2 当遇到 ASCII 表中没有的字符的时候,默认会把它们使用 utf-8 编码来存储,但是 gbk 编码表无法对 utf-8 编码进行解码,这句话你可能需要读完文章才能理解。 」 这个例子里出错的原因并不是 gbk 编码表无法对 utf-8 编码进行解码。注意看这里报的错是 UnicodeDecodeError: 'ascii' codec can't decode,说的是 Python 无法用 ascii 编码来解码 '你好',和 gbk (gb2312) 编码没关系。而且 encode 是执行编码操作不是解码操作,你是在用 gb2312 对字符串进行编码,不是你文中说的「 gbk 编码表……进行解码」。 这里出错的真正原因是:你在 Python 2 下对 str 类型的字符串进行了 encode 操作,encode 操作只对 unicode 类型字符串才有意义( Python 3 里甚至不允许对非 unicode 字符串 (bytes) 进行 encode 操作,也不允许对 unicode 字符串 (str) 进行 decode 操作),所以 Python 2 在这里会隐式地尝试将 str 类型的 '你好' decode 为 unicode 类型字符串后再进行你要的 encode,这个隐式的 decode 操作使用的编码是 Python 2 的默认编码—— ascii,Python 的默认编码可以通过以下命令查看: >>> import sys >>> sys.getdefaultencoding() 'ascii' 所以执行 '你好'.encode('gb2312') 时相当于执行了: '你好'.decode('ascii').encode('gb2312') ascii 无法解码中文,所以报了 UnicodeDecodeError 错,此时还没有真正执行 encode('gb2312'),所以例子和你的解释并不适用。 正确的例子应该是: >>> '\xe4\xbd\xa0\xe5\xa5\xbd'.decode('gbk') u'\u6d63\u72b2\u30bd' >>> u'\u6d63\u72b2\u30bd' == u'你好' False 不用 '你好'.decode('gbk') 来举例是因为正如上文 1 所说,这段代码在中文 Windows 系统下是没有编码错误的: >>> '你好'.decode('gbk') == u'你好' True 而 '\xe4\xbd\xa0\xe5\xa5\xbd'.decode('gbk') 这个例子你会发现 Python 2 是能顺利运行没有报错的,并不像你说的「 gbk 编码表无法对 utf-8 编码进行解码」那样出现 UnicodeDecodeError 错误。甚至这个结果是能直接 print 出来的: >>> print('\xe4\xbd\xa0\xe5\xa5\xbd'.decode('gbk')) 浣犲ソ 这是因为 '你好' 的 utf-8 编码和 '浣犲ソ' 的 gbk 编码是重合的,都是 '\xe4\xbd\xa0\xe5\xa5\xbd': >>> u'你好'.encode('utf-8') '\xe4\xbd\xa0\xe5\xa5\xbd' >>> u'浣犲ソ'.encode('gbk') '\xe4\xbd\xa0\xe5\xa5\xbd' 所以 gbk 编码表其实是可以对部分 utf-8 编码的字符串进行解码的,只是解码的结果不是我们想要的,也就是出现了乱码问题。 3-- 「 另外常见编码错误就是使用错误的编码保存字符串,例如使用 ASCII 表保存”你好”,因为 ASCII 表里面没有对应的字符,它不知道如何保存。 >>> '你好'.encode('ascii') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128) 」 这个例子应该是在 Python 3 下执行的结果,'你好' 得是 unicode 类型字符串对其 encode('ascii') 才会报 UnicodeEncodeError 错误,否则在 Python 2 下应该如 2 的例子一样报的是 UnicodeDecodeError 错误: >>> '你好'.encode('ascii') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128) 也就是相当于执行了: '你好'.decode('ascii').encode('ascii') 正确的例子应该是: >>> u'你好'.encode('ascii') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128) -- 我以前也写过篇和 Python 2 中文 Unicode 编码问题有关的文章,供你参考: https://www.v2ex.com/t/163786 |