编码期间出现 UnicodeDecodeError?

use*_*028 3 python unicode

我们遇到了一个问题(http://wiki.python.org/moin/UnicodeDecodeError对此进行了描述)——阅读第二段“...自相矛盾...”。

具体来说,我们正在尝试将字符串上转换为 unicode,但我们收到了 UnicodeDecodeError。

例子:

   >>> unicode('\xab')
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   UnicodeDecodeError: 'ascii' codec can't decode byte 0xab in position 0: ordinal not in range(128)
Run Code Online (Sandbox Code Playgroud)

但当然,这工作起来没有任何问题

   >>> unicode(u'\xab')
   u'\xab'
Run Code Online (Sandbox Code Playgroud)

当然,这段代码是为了演示转换问题。在我们的实际代码中,我们没有使用字符串文字,我们不能只在前面添加 unicode 'u' 前缀,而是我们正在处理从 os.walk() 返回的字符串,并且文件名包含上述值。由于我们无法在不调用 unicode() 构造函数的情况下将值强制转换为 unicode,因此我们不确定如何继续。

发生的一种非常可怕的黑客行为是编写我们自己的 str2uni() 方法,如下所示:

def str2uni(val):
    r"""brute force coersion of str -> unicode"""
    try:
        return unicode(src)
    except UnicodeDecodeError:
        pass
    res = u''
    for ch in val:
       res += unichr(ord(ch))
    return res
Run Code Online (Sandbox Code Playgroud)

但在我们这样做之前——想看看其他人是否有任何见解?

更新

我发现每个人都在关注我如何得到我发布的示例,而不是结果。叹息 - 好吧,这是导致我花费数小时将问题简化为我上面分享的最简单形式的代码。

for _,_,files in os.walk('/path/to/folder'):
    for fname in files:
        filename = unicode(fname)
Run Code Online (Sandbox Code Playgroud)

当文件名具有以下值“3\xab Floppy (A).link”时,该代码段会引发 UnicodeDecodeError 异常

要亲自查看错误,请执行以下操作:

   >>> unicode('3\xab Floppy (A).link')
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   UnicodeDecodeError: 'ascii' codec can't decode byte 0xab in position 1: ordinal not in range(128)
Run Code Online (Sandbox Code Playgroud)

更新

我真的很感谢每个试图提供帮助的人。我也很欣赏大多数人会犯一些与字符串/unicode 处理相关的非常简单的错误。但我想强调对UnicodeDecodeError异常的引用。我们在调用 unicode() 构造函数时得到了这个!

我相信前面提到的 Wiki 文章http://wiki.python.org/moin/UnicodeDecodeError中描述了根本原因。从第二段往下阅读“矛盾的是,编码时可能会发生 UnicodeDecodeError ”。维基百科的文章非常准确地描述了我们正在经历的事情——但是虽然它详细阐述了问题,但它没有提出解决方案的建议。

事实上,第三段以以下令人震惊的承认“与 UnicodeEncodeError 的类似情况不同,这样的失败总是无法避免......”开头。

由于作为一名开发人员,我不习惯“无法从这里到达那里”的信息,因此我认为有兴趣在 Stack Overflow 上了解其他人的经验。

Tim*_*ker 5

我认为您混淆了 Unicode 字符串和 Unicode 编码(如 UTF-8)。

os.walk(".")返回文件名(和目录名等)作为在当前代码页中编码的字符串。它将默默地删除 当前代码页中不存在的字符(请参阅此问题以获取一个引人注目的示例)。

因此,如果您的文件/目录名称包含编码范围之外的字符,那么您肯定需要使用 Unicode 字符串来指定起始目录,例如通过调用os.walk(u"."). 然后您不需要(也不应该)unicode()再调用结果,因为它们已经Unicode 字符串。

如果不这样做,您首先需要解码文件名(如mystring.decode("cp850")),这将为您提供一个 Unicode 字符串:

>>> "\xab".decode("cp850")
u'\xbd'
Run Code Online (Sandbox Code Playgroud)

然后您可以将其编码为 UTF-8 或任何其他编码。

>>> _.encode("utf-8")
'\xc2\xbd'
Run Code Online (Sandbox Code Playgroud)

如果您仍然困惑为什么unicode("\xab")会引发解码错误,也许以下解释会有所帮助:

"\xab"是一个编码字符串。Python 无法知道那是哪种编码,但在将其转换为 Unicode 之前,需要先对其进行解码。如果没有您的任何指定,unicode()则假设它是用 ASCII 编码的,当它尝试在此假设下对其进行解码时,它会失败,因为它\xab不是 ASCII 的一部分。因此,要么您需要找出您的文件系统和调用unicode("\xab", encoding="cp850")或其他什么正在使用哪种编码,要么首先从 Unicode 字符串开始。