代码之家  ›  专栏  ›  技术社区  ›  dnolen

Python UTF8字符串混淆

  •  1
  • dnolen  · 技术社区  · 15 年前

    我在这个问题上绞尽脑汁已经有一段时间了,我读了很多文章,但这个问题并不清楚。我的数据库中存储了一堆字符串,想象一下:

    x = '\xd0\xa4'
    y = '\x92'
    

    在Python shell中,我得到了以下信息:

    print x
    Ф
    print y
    ?
    

    print unicode(x, 'utf8')
    Ф
    

    但不是这样:

    unicode(y, 'utf8')
    UnicodeDecodeError: 'utf8' codec can't decode byte 0x92 in position 0: unexpected code byte
    

    我的感觉是,由于Django试图将字符串转换为unicode,我们的字符串正在被破坏,但我只是在猜测这一点。任何见解或解决方法都值得赞赏。

    更新

    5 回复  |  直到 15 年前
        1
  •  7
  •   John Machin Santi    15 年前

    看起来你有打字错误;应该是 x = '\xd0\xa4'

    print y 产生 ? .你把“Python控制台”叫做什么??它似乎在“替换”模式下运行,并替换“?”。。。你确定这是一个平原吗而不是白人在黑钻石里面?你为什么这么说这正是你期望看到的?

    更新:

    那不是撇号。这段数据似乎是使用cp125X(又名windows-125X)编码之一进行编码的。使用cp1252(常见嫌疑人)进行说明:

    IDLE 2.6.4      
    >>> import unicodedata
    >>> uc = '\x92'.decode('cp1252')
    >>> print repr(uc)
    u'\u2019'
    >>> print uc
    ’
    >>> unicodedata.name(uc)
    'RIGHT SINGLE QUOTATION MARK'
    >>> 
    

    print repr(bad_string) 。向我们展示您运行的代码,以及repr()的输出。还要告诉我们Python的版本、平台(基于Windows或unix)以及数据库软件的版本。以及CREATE TABLE语句中与相关列相关的部分。

    另请阅读 this this .

        2
  •  5
  •   user3850 user3850    15 年前

    \x92 不是有效的utf-8编码字符。

    您没有注意到这一点,因为您使用简单(非unicode)字符串 x y

    还有第三个参数 unicode() 这告诉python在编码(解码)错误的情况下应该做什么:

    >>> unicode('\x92', 'utf8', 'replace')
    u'\ufffd'
    >>> print _
    �
    
        3
  •  4
  •   user180247 user180247    15 年前

    我认为除ASCII子集之外的任何unicode字符在UTF-8中都有多字节表示 y 作为每个字符字符串的单字节,而不是UTF-8字符串,这是有意义的。由于单个字节在0x00到0x7F ASCII范围之外,编解码器将需要额外的字节或更多字节来转换为“实”unicode字符。

    不过,我已经不像以前那样熟悉Python了,我对这个答案也没有信心。

    编辑

        4
  •  2
  •   Thanatos    15 年前

    我现在明白你的困惑了。让我们看看这个:

    x = '\xd0\xa4'
    y = '\x92'
    

    print x D0 A4 ,它尝试将其解码为UTF-8,并得到一个“·”。如果我把终端换成ISO-8859-1(“latin1”),我说 打印x D0 A4 使用ISO-8859-1 D0 A4 而且

    现在,为了 print y 这不是UTF-8字符串,所以我的终端无法解码。它通过打印“”向我显示了这个错误。我想知道你是否看到“或”?-您可能应该看到前者,但这取决于您的终端在遇到不良输出时的表现。

    你的终端编码应该匹配任何 $LANG 你的程序应该以任何编码输出数据 $LANG 指定。现今 ???.UTF-8 ,其中 ??? 变化。(我的是 en_US.UTF-8

    现在,当你说 unicode(y, 'utf8') ,Python尝试将其解码为UTF-8,并适当地抛出异常。

        5
  •  1
  •   AndiDog    15 年前
    0x92 (hex) = 10 010010 (binary)
    

    我猜您的数据库使用了每个字符一个字节的编码(例如拉丁语-1)。如果您自己对数据库查询进行编码,则必须确保连接编码正确或字符串解码正确。对于Django模型,一切都应该自动工作。