我正在尝试解析包含一些数据的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)
答案 0 :(得分:12)
这就是发生的事情:
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
'אבגדה'
[/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
。