在python中,strjoin=str1+str2,如果str1(ascii编码)和str2(utf-8编码)的编码方式不一致,比如,那么strjoin将是个'奇怪的字符串',自身就有两种不同的编码.
这种情况往往导致strjoin显示为乱码.
在ruby中,当执行strjoin=str1+str2时,ruby会检验str1编码和str2的编码,以及这两个编码是否兼容(例如,utf-8编码就可以兼容ascii编码),如果兼容,就统一使用兼容性的编码作为strjoin的编码.
检查编码兼容性的伪代码如下:
Encoding.compatible?(coding1, coding2)
如果coding1兼容coding2编码,则返回coding1;如果coding2兼容coding1,则返回coding2;如果coding1和coding2没有兼容性,则返回false.
我想问的是,python中是否有类似的方法或者模块,来检查编码的兼容性?多谢!
三叔2016-10-26 09:19:31
以Python2.7为例说明一下Python在字符串拼接时的编码机制。
Python2.7字符串有两种类型unicode和str,unicode和unicode字符串,str和str字符串
拼接时最终结果还是原来的类型;当unicode和str进行拼接时,会将str类型的字符串按
default encoding解码为unicode后再拼接。
str类型的字符串实际上可以是任意编码的字节串,解码和拼接过程不会做实际的编码检
查,也没有信息去检查(有编码检测的模块如chardet,但也只会给一个猜测可信度)。
下面是详细描述,稍微有点冗长:
1 Python2.7字符串类型
Python2.7字符串有两种类型unicode和str(可以认为是字节串)
>>> a = 'abc' >>> type(a)>>> a = u'abc' >>> b = '中国' # 我的终端是utf-8编码,所以b是utf-8编码的字节串 >>> b = u'中国'
2 Python2.7字符串编解码
unicode编码的字符串可以通过encode函数编码成各种其他编码的字符串(类型为str的字节串)
>>> a = u'中国' >>> a_utf8 = a.encode('utf-8') >>> a_utf8, type(a_utf8) ('\xe4\xb8\xad\xe5\x9b\xbd',) >>> a_gbk = a.encode('gbk') >>> a_gbk ('\xd6\xd0\xb9\xfa', )
其他编码的字节串可以通过decode函数解码成unicode字符串:
>>> a_unicode = a_utf8.decode('utf-8') >>> a_unicode, type(a_unicode) (u'\u4e2d\u56fd',) >>> a_unicode = a_gbk.decode('gbk') >>> a_unicode, type(a_unicode) (u'\u4e2d\u56fd', )
3 Python2.7字符串拼接
字符串拼接用到Python的default encoding。
可以通过下面代码获取default encoding:
>>> import sys >>> sys.getdefaultencoding() # 默认缺省编码是ascii 'ascii'
可以通过下面代码设置default encoding:
>>> import sys >>> reload(sys) >>> sys.setdefaultencoding('utf-8') >>> sys.getdefaultencoding() 'utf-8'
字符串有两种类型unicode和str,所以拼接一共有4中场景:
3.1 unicode + unicode
这个比较简单,直接拼接,结果仍然是unicode >>> str1 = u'a' >>> str2 = u'中国' >>> strjoin = str1 + str2 >>> strjoin u'a\u4e2d\u56fd' >>> print strjoin a中国
3.2 unicode + str和str + unicode (行为一致)
首先将类型为str的字符串使用default encoding解码为unicode,然后拼接。
解码过程不会检查str字节串实际是什么编码,也没有信息可以检查。
假设str1为unicode,str2为str,则
str1 + str2 会转变为 str1 + str2.decode(sys.getdefaultencoding())
# 默认default encoding为ascii >>> str1 = u'a' >>> str2 = 'b' >>> strjoin = str1 + str2 >>> strjoin u'ab' >>> str1 = u'a' # str2为utf-8编码的字节串,类型为str; # 为了明显起见也可以改为 str2 = u'中国'.encode('utf-8') >>> str2 = '中国' >>> strjoin = str1 + str2 Traceback (most recent call last): File "", line 1, in UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128) # 这里的错误发生在对str2.decode('ascii'), # 如果将default encoding改为utf-8就不会有问题了 >>> import sys >>> reload(sys) >>> sys.setdefaultencoding('utf-8') >>> strjoin = str1 + str2 >>> strjoin u'a\u4e2d\u56fd' >>> print strjoin a中国 # 实际在多个字符串拼接时,只要其中有unicode字符串,其他str字符串都会先解码为unicode后再进行拼接。
3.3 str + str
这个也简单,直接拼接,结果仍然是str。不会去检查str字节串实际是什么编码。
>>> str1 = 'a' >>> str2 = '中国' >>> strjoin = str1 + str2 >>> strjoin, type(strjoin) ('a\xe4\xb8\xad\xe5\x9b\xbd',) >>> str1 = u'中国'.encode('utf-8') >>> str2 = u'中国'.encode('gbk') >>> str1, str2 ('\xe4\xb8\xad\xe5\x9b\xbd', '\xd6\xd0\xb9\xfa') >>> strjoin = str1 + str2 '\xe4\xb8\xad\xe5\x9b\xbd\xd6\xd0\xb9\xfa' >>> print strjoin 中国?й? # 由于系统标准输出编码为UTF-8,所以gbk编码的字节串显示为乱码 >>> sys.stdout.encoding 'UTF-8'