我已经开了一段时间了,我已经阅读了很多文章,问题并没有更明确。我有一堆字符串存储在我的数据库中,想象如下:
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,但我只是在猜测。任何见解或变通方法都表示赞赏。
UPDATE :当我查看包含'\ x92'值的行的数据库时,我将此字符视为'。撇号。我正在使用Unicode UTF-8编码查看数据库的内容。
答案 0 :(得分:7)
看起来你有一个错字;应该是x = '\xd0\xa4'
。如果您使用实际运行的内容和输出中出现的内容的复制粘贴,它会非常有用。
“\ x92”不是有效的UTF-8字符串。这解释了你得到的例外。
更多的谜题是print y
生成?
的原因。你叫什么叫“Python控制台”?它似乎是在“替换”模式下运行而代以“?” ......你确定这是一个简单的“?”而不是白色的“?”黑钻里面?为什么这么说“?”正是你期望看到的?
更新:您现在说“”当我在包含'\ x92'值的行查看数据库时,我将此字符视为'。撇号。我正在查看使用Unicode UTF-8编码的数据库内容。“”“
那不是撇号。看来这段数据是使用cp125X(aka 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'
>>>
不是“使用Unicode UTF-8编码查看数据库的内容”(无论这意味着什么),而是尝试编写一小段Python代码来提取有问题的字符串,然后执行print repr(bad_string)
。向我们展示您运行的代码,以及repr()的输出。还告诉我们哪个版本的Python,什么平台(基于Windows或unix),以及什么版本的数据库软件。并且CREATE TABLE语句的部分与相关列相关。
答案 1 :(得分:5)
\x92
不是有效的utf-8编码字符。
您没有注意到,因为您使用x
和y
的简单(非unicode)字符串,直到您尝试将它们解码为unicode字符串。当你打印它们时,它们被简单地“按原样”转储到终端,终端本身根据其编码设置解释字节。
unicode()
有第三个参数告诉python在编码(解码)错误时该怎么做:
>>> unicode('\x92', 'utf8', 'replace')
u'\ufffd'
>>> print _
�
答案 2 :(得分:4)
我认为除了ASCII子集之外的任何unicode字符都有UTF-8中的多字节表示。您的y
作为每个字符的单字节字符串有意义,但不是UTF-8字符串。因为单个字节在0x00到0x7F ASCII范围之外,所以编解码器将需要一个或多个字节来转换为“真正的”unicode字符。
我对Python的熟悉程度与以前不同,我对这个答案并不自信。
EDIT hops是IMO的最佳答案。
答案 3 :(得分:2)
我现在看到你感到困惑的地方。我们来看看:
x = '\xd0\xa4'
y = '\x92'
如果我print x
,我会得到Ф.这是因为我的终端使用UTF-8作为其字符编码。因此,当它获得D0 A4
时,它会尝试将其解码为UTF-8,并获得“Ф”。如果我改变我的终端使用,比如ISO-8859-1(“latin1”),我说print x
,我的终端将尝试使用ISO-8859-1解码D0 A4
, D0 A4
也是一个有效的ISO-8859-1字符串,它会解码,但这次是“Ф”。
现在,print y
。这不是UTF-8字符串,所以我的终端无法对此进行解码。在我的例子中,它通过打印“ ”向我显示了这个错误。我想知道你是否看到“ ”或“?” - 您应该看到前者,但这取决于您的终端在输出不良时的作用。
您的终端的编码应该与$LANG
所说的匹配,并且您的程序应该以{{1}}指定的任何编码输出数据。如今,$LANG
通常为$LANG
,其中???.UTF-8
会有所不同。 (我的是???
)
现在,当你说en_US.UTF-8
时,Python会尝试将其解码为UTF-8,并适当地抛出异常。
我正在使用Gnome终端,可以通过转到终端→设置字符编码来更改我的字符编码
答案 4 :(得分:1)
0x92 (hex) = 10 010010 (binary)
由于UTF-8可以在一个字节中表示010010,因此“标题”必须为0( - > 00010010)而不是10(它永远不能是第一个字节的标题)。字符可能不会用超过需要的字节来表示,因此“\ x92”不是有效的UTF-8编码字符串。
我猜你的数据库使用一些每字节一个字节的编码(比如latin-1)。如果您自己编写数据库查询,则必须确保连接编码正确或正确解码字符串。使用Django模型,一切都应该自动运行。