【问题标题】:Python 3: os.walk() file paths UnicodeEncodeError: 'utf-8' codec can't encode: surrogates not allowedPython 3: os.walk() 文件路径 UnicodeEncodeError: 'utf-8' codec can't encode: surrogates not allowed
【发布时间】:2015-02-06 14:37:31
【问题描述】:

这段代码:

for root, dirs, files in os.walk('.'):
    print(root)

给我这个错误:

UnicodeEncodeError: 'utf-8' codec can't encode character '\udcc3' in position 27: surrogates not allowed

如何遍历文件树而不得到这样的有毒字符串?

【问题讨论】:

  • python 3 的哪个版本?
  • Python 3.4.0(默认,2014 年 4 月 11 日,13:05:11)在 Ubuntu 14.04 上。我有LANG=en_US.UTF-8
  • print(root.encode("utf-8", "surrogateescape"))有什么作用吗?
  • stackoverflow.com/questions/38147259/… 对错误消息的含义进行了更详细的解释。

标签: python python-3.x unicode unicode-string python-unicode


【解决方案1】:

在 Linux 上,文件名“只是一堆字节”,不一定以特定编码进行编码。 Python 3 尝试将所有内容都转换为 Unicode 字符串。在这样做的过程中,开发人员想出了一个方案,将字节字符串转换为 Unicode 字符串并在不丢失且不知道原始编码的情况下返回。他们使用部分代理来编码“坏”字节,但在打印到终端时,普通的 UTF8 编码器无法处理它们。

例如,这是一个非 UTF8 字节字符串:

>>> b'C\xc3N'.decode('utf8','surrogateescape')
'C\udcc3N'

可以无损地与Unicode相互转换:

>>> b'C\xc3N'.decode('utf8','surrogateescape').encode('utf8','surrogateescape')
b'C\xc3N'

但是不能打印:

>>> print(b'C\xc3N'.decode('utf8','surrogateescape'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'utf-8' codec can't encode character '\udcc3' in position 1: surrogates not allowed

您必须弄清楚要如何处理具有非默认编码的文件名。也许只是将它们编码回原始字节并用未知的替换解码它们。使用它进行显示,但保留原始名称以访问文件。

>>> b'C\xc3N'.decode('utf8','replace')
C�N

os.walk 也可以接受字节字符串,并且将返回字节字符串而不是 Unicode 字符串:

for p,d,f in os.walk(b'.'):

然后你就可以随意解码了。

【讨论】:

  • 我最终做了bad_string.encode('utf-8', 'surrogateescape').decode('ISO-8859-1')
  • @Collin Anderson 您是如何检测到错误字符串的出现,您是如何捕获错误的?
  • 对我有用的是"bad string".encode('utf-8', 'surrogateescape').decode('utf-8')
  • 你获得支持,Python 为格兰芬多获得 -10 分。
  • @DoTheEvo Collins hack 适用于好字符串和坏字符串。它之所以有效,是因为每个字节都是“ISO-8859-1”中的有效代码点。但是,对于没有相同 utf-8 和 'ISO-8859-1' 编码的字符,它会打印出奇怪的东西。
【解决方案2】:

我最终将一个字节字符串传递给 os.walk(),这显然会返回字节字符串而不是不正确的 unicode 字符串

for root, dirs, files in os.walk(b'.'):
    print(root)

【讨论】:

    【解决方案3】:

    尝试使用这行代码:

    "bad string".encode('utf-8', 'replace').decode()
    

    【讨论】:

      【解决方案4】:

      使用sedgrep 过滤:

      set | sed -n '/^[a-zA-Z0-9_]*=/p'
      # ... or ...
      set | grep '^[a-zA-Z0-9_]*='
      # ... or ...
      set | egrep '^[_[:alnum:]]+='
      

      这对你的变量名有多疯狂很敏感。最后一个版本应该可以处理最疯狂的事情。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-02-01
        • 2017-05-10
        • 2015-12-03
        • 1970-01-01
        • 2018-04-18
        • 2019-03-10
        • 2018-08-14
        相关资源
        最近更新 更多