【问题标题】:python utf-8 encoding throws UnicodeDecodeError despite "errors = 'replace' "尽管“errors = 'replace'”,python utf-8 编码仍会引发 UnicodeDecodeError
【发布时间】:2015-07-08 17:38:43
【问题描述】:

我正在尝试写出一些文本,并尽可能使用以下代码将其编码为 utf-8:

outf.write((lang_name + "," + (script_name or "") + "\n").encode("utf-8", errors='replace'))

我收到以下错误:

File "C:\Python27\lib\encodings\cp1252.py", line 15, in decode 
    return codecs.charmap_decode(input,errors,decoding_table)
UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 6: character maps to <undefined>

我认为我的编码调用中的 errors='replace' 部分可以处理这个问题?

fwiw,我只是用

打开文件
outf = open(outfile, 'w')

没有明确声明编码。

print repr(outf) 

产生:

<open file 'myfile.csv', mode 'w' at 0x000000000315E930>

我将写语句分离为单独的连接、编码和文件写入:

outstr = lang_name + "," + (script_name or "") + "\n"
encoded_outstr = outstr.encode("utf-8", errors='replace')
outf.write(encoded_outstr)

这是引发异常的串联。

字符串是,通过print repr(foo)

lang_name: 'G\xc4\x81ndh\xc4\x81r\xc4\xab'
script_name: u'Kharo\u1e63\u1e6dh\u012b'

进一步的侦探工作表明,我可以毫无困难地将其中任何一个与普通的 ascii 字符串连接起来 - 它将它们都放入同一个字符串中,这会破坏事物。

【问题讨论】:

  • 这里的script_codescript_name 是什么?你有一个解码错误,不是编码,所以一个或两个都是字节串,而不是unicode对象。
  • Unicode 字符串上的 .encode("utf-8") 将始终有效,因为所有 Unicode 点都可以表示为 UTF8,因此在这种情况下 errors='replace' 是多余的。
  • 接下来,这里的outf 是什么?你是怎么打开那个物体的?您的代码尝试解码字节串 as CP1252 是可疑的。对于隐式解码,这意味着您使用了sys.setdefaultencoding()(一个很大的禁忌),但如果outf 不是一个常规的Python 2 文件对象,而是一个codecsio 文件对象,那将解释例外。
  • @MartijnPieters 我展示了我是如何打开 outf 的。 script_code 和 script_name 是从网页中抓取的字符串。
  • 我认为如果他之前将s = script_code + "," + (script_name or "") + "\n" 放在行中,那将引发异常。

标签: python encoding utf-8 cp1252


【解决方案1】:

所以,问题在于您将字节字符串 'G\xc4\x81ndh\xc4\x81r\xc4\xab' 和 Unicode 字符串 u'Kharo\u1e63\u1e6dh\u012b' 连接起来。

为了做到这一点,Python 2.7 尝试使用其默认编码解码字节串,将其转换为 Unicode。您的默认编码是 cp1252 而不是 ASCII,原因我无法从这里知道,但无论如何它都会失败,就像它是 ASCII 一样,因为该字符串是 UTF8。

您最好的解决方案可能是通过首先更改变量获取这些值的方式来确保不会发生这种情况。

如果你不能,因为无论如何你都在下一行编码为 UTF8,所以只编码 script_name 可能是最简单的:

encoded_outstr = lang_name + b"," + (script_name.encode('utf-8') or b"") + b"\n"

请注意,我使用 b"," 明确地将这些字符串文字设为字节字符串,而不是 Unicode 字符串;如果你使用from __future__ import unicode_literals 来兼容 Python 3,那么它们默认是 Unicode,问题会再次出现。

【讨论】:

  • 问题是我不认为循环的每次迭代的编码都是一致的(!)是否有编程方法来测试编码是什么?我有点认为这是一个开放的研究问题;-)
【解决方案2】:

当你连接一个字节字符串和一个 Unicode 字符串时,Python 2 会首先尝试将字节字符串转换为 Unicode。如果字节字符串包含\x80\xff 范围内的任何非ASCII 字符,则自动转换将失败并显示您显示的错误。请注意,它显示的是 can't decode,而不是 can't encode - 这表明在您对 encode 的调用中没有发生错误。

解决方案是自己将decode字节字符串转换成Unicode,使用正确的代码页,这样所有连接的输入都是Unicode字符串。

outstr = lang_name.decode("utf-8") + u"," + (script_name or u"") + u"\n"

【讨论】:

    猜你喜欢
    • 2018-05-05
    • 1970-01-01
    • 2017-03-25
    • 1970-01-01
    • 1970-01-01
    • 2018-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多