【问题标题】:Python string decoding issuePython字符串解码问题
【发布时间】:2011-01-24 06:26:39
【问题描述】:

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

最后我需要知道编码,这样我才能对字符串进行 unicode 编码,打印它们,也许稍后将它们放入数据库中。

我尝试使用 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)

【问题讨论】:

标签: python string unicode character-encoding


【解决方案1】:

这是正在发生的事情:

  • sampleString 是一个字节串(cp1255 编码)
  • sampleString.decode("cp1255") 将字节串解码(decode==bytes -> unicode string)为 unicode 串
  • print sampleString.decode("cp1255") 尝试将 unicode 字符串打印到标准输出。 Print 必须encode 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表示A在utf-8中,ה在cp424.

encode 方法有一个可选的字符串参数,您可以使用它来指定当编码不能表示字符时应该发生什么 (documentation)。支持的策略是严格(默认)、忽略、替换、xmlcharref 和反斜杠替换。你甚至可以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'

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 运行 chcp 65001 对此无济于事,因为错误是 Python 本身正在尝试使用其默认编码 ASCII 隐式编码 print 的 unicode 字符串。
      【解决方案4】:

      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 [...]
      

      【讨论】:

      • 因为 someString 显然不是 unicode 字符串。如果是, print repr(someString) 将显示 u'...'。
      • @codeape:是的,但他实际上从未向我们展示过 repr(someString) 的结果,是吗?他只向我们展示了 repr(sampleString),这可能完全是另一回事。
      • 我假设 sampleString 与 someString 是同一类。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-05
      • 2014-01-08
      • 2012-02-22
      • 1970-01-01
      • 2011-07-14
      • 2020-04-04
      • 1970-01-01
      相关资源
      最近更新 更多