Python字符串解码问题

时间:2010-03-05 19:32:04

标签: python string unicode character-encoding

我正在尝试解析包含一些数据的CSV文件,主要是数字但有一些字符串 - 我不知道它们的编码,但我知道它们是希伯来语。

最终我需要知道编码,这样我就可以对字符串进行解码,打印它们,然后将它们放入数据库中。

我尝试使用Chardet,声称字符串是Windows-1255(cp1255),但尝试执行print someString.decode('cp1255')会产生臭名昭着的错误:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 1-4: ordinal not in range(128)

我尝试了所有其他编码,但无济于事。此外,该文件绝对有效,因为我可以在Excel中打开CSV并看到正确的数据。

知道如何正确解码这些字符串吗?


编辑:这是一个例子。其中一个字符串看起来像这样(希伯来字母的前五个字母):

print repr(sampleString)
#prints:
'\xe0\xe1\xe2\xe3\xe4'

(使用Python 2.6.2)

4 个答案:

答案 0 :(得分:12)

这就是发生的事情:

  • sampleString是一个字节字符串(cp1255编码)
  • sampleString.decode("cp1255")解码(decode == bytes - > unicode string)字节字符串为unicode字符串
  • print sampleString.decode("cp1255")尝试将unicode字符串打印到stdout。打印必须编码 unicode字符串才能执行此操作(encode == unicode string - > bytes)。您看到的错误意味着python print语句无法将给定的unicode字符串写入控制台的编码。 sys.stdout.encoding是终端的编码。

所以问题是你的控制台不支持这些字符。您应该能够调整控制台以使用其他编码。有关如何操作的详细信息取决于您的操作系统和终端程序。

另一种方法是手动指定要使用的编码:

print sampleString.decode("cp1255").encode("utf-8")

另见:

您可以尝试的简单测试程序:

import sys
print sys.stdout.encoding
samplestring = '\xe0\xe1\xe2\xe3\xe4'
print samplestring.decode("cp1255").encode(sys.argv[1])

在我的utf-8终端上:

$ python2.6 test.py utf-8
UTF-8
אבגדה

$ python2.6 test.py latin1
UTF-8
Traceback (most recent call last):
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-4: ordinal not in range(256)

$ python2.6 test.py ascii
UTF-8
Traceback (most recent call last):
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-4: ordinal not in range(128)

$ python2.6 test.py cp424
UTF-8
ABCDE

$ python2.6 test.py iso8859_8
UTF-8
�����

latin-1和ascii的错误消息表示字符串中的unicode字符无法在这些编码中表示。

注意最后两个。我将unicode字符串编码为cp424和iso8859_8编码(http://docs.python.org/library/codecs.html#standard-encodings上列出的支持希伯来字符的两种编码)。我使用这些编码也不例外,因为希伯来语unicode字符在编码中有一个表示。

但是当我的utf-8终端以不同于utf-8的编码接收字节时会非常困惑。

在第一种情况下(cp424),我的UTF-8终端显示ABCDE,这意味着A的utf-8表示对应于ה的cp424表示,即字节值65表示utf-8中的A和הin cp424。

encode方法有一个可选的字符串参数,可用于指定编码无法表示字符(documentation)时应发生的情况。支持的策略是严格(默认),忽略,替换,xmlcharref和backslashreplace。你甚至可以add your own custom strategies

另一个测试程序(我在字符串周围打印引号以更好地显示忽略行为):

import sys
samplestring = '\xe0\xe1\xe2\xe3\xe4'
print "'{0}'".format(samplestring.decode("cp1255").encode(sys.argv[1], 
      sys.argv[2]))

结果:

$ python2.6 test.py latin1 strict
Traceback (most recent call last):
  File "test.py", line 4, in <module>
    sys.argv[2]))
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-4: ordinal not in range(256)
[/tmp]
$ python2.6 test.py latin1 ignore
''
[/tmp]
$ python2.6 test.py latin1 replace
'?????'
[/tmp]
$ python2.6 test.py latin1 xmlcharrefreplace
'&#1488;&#1489;&#1490;&#1491;&#1492;'
[/tmp]
$ python2.6 test.py latin1 backslashreplace
'\u05d0\u05d1\u05d2\u05d3\u05d4'

答案 1 :(得分:3)

当您使用someString.decode('cp1255')将字符串解码为unicode时,您将获得unicode中某些希伯来语文本的抽象表示。 (这部分成功发生!)当您使用print时,您需要一个特定编码的具体编码表示。看起来您的问题不在于解码,而在于print

要打印,如果您的终端了解cp1255或“print someString”,则只需print someString.decode('cp1255').encode('the_encoding_your_terminal_does_understand')。如果您不需要将结果打印作为希伯来语读取,print repr(someString.decode('cp1255'))也可以为您提供有意义的抽象unicode字符串表示。

答案 2 :(得分:0)

someString可能不是普通的字符串,而是unicode字符串,就像你让我们相信你的sampleString

>>> print '\xe0\xe1\xe2\xe3\xe4'.decode('cp1255')
<hebrew characters>

>>> print u'\xe0\xe1\xe2\xe3\xe4'.decode('cp1255')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "[...]/encodings/cp1255.py", line 15, in decode
    return codecs.charmap_decode(input,errors,decoding_table)
UnicodeEncodeError: 'ascii' codec can't encode characters [...]

答案 3 :(得分:0)

您在打印时遇到编码错误,因此很可能它解码正常,您无法正确打印出结果。尝试在启动Python代码之前在命令提示符下运行chcp 65001