ホームページ  >  に質問  >  本文

python中怎么判断编码的兼容性?

在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中是否有类似的方法或者模块,来检查编码的兼容性?多谢!


高洛峰高洛峰2939日前669

全員に返信(1)返信します

  • 三叔

    三叔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'


    返事
    0
  • キャンセル返事