0

我在 Ubuntu 12 x64 上使用 Python 2.7.3。

我的文件系统上的一个文件夹中有大约 200,000 个文件。一些文件的文件名包含 html 编码和转义字符,因为这些文件最初是从网站下载的。以下是示例:

牙买加%2008%20114.jpg
thai_trip_%E8%B0%83%E6%95%B4%E5%A4%A7%E5%B0%8F%20RAY_5313.jpg

我编写了一个简单的 Python 脚本,它遍历文件夹并重命名所有文件名中带有编码字符的文件。新文件名是通过简单地解码构成文件名的字符串来实现的。

该脚本适用于大多数文件,但是对于某些文件,Python 会阻塞并吐出以下错误:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 11: ordinal not in range(128)
Traceback (most recent call last):
  File "./download.py", line 53, in downloadGalleries
    numDownloaded = downloadGallery(opener, galleryLink)
  File "./download.py", line 75, in downloadGallery
    filePathPrefix = getFilePath(content)
  File "./download.py", line 90, in getFilePath
    return cleanupString(match.group(1).strip()) + '/' + cleanupString(match.group(2).strip())
  File "/home/abc/XYZ/common.py", line 22, in cleanupString
    return HTMLParser.HTMLParser().unescape(string)
  File "/usr/lib/python2.7/HTMLParser.py", line 472, in unescape
    return re.sub(r"&(#?[xX]?(?:[0-9a-fA-F]+|\w{1,8}));", replaceEntities, s)
  File "/usr/lib/python2.7/re.py", line 151, in sub
    return _compile(pattern, flags).sub(repl, string, count)

这是我的 cleanupString 函数的内容:

def cleanupString(string):
    string = urllib2.unquote(string)

    return HTMLParser.HTMLParser().unescape(string)

这是调用 cleanupString 函数的代码片段(此代码与上述回溯中的代码不同,但会产生相同的错误):

rootFolder = sys.argv[1]
pattern = r'.*\.jpg\s*$|.*\.jpeg\s*$'
reobj = re.compile(pattern, re.IGNORECASE)
imgs = []

for root, dirs, files in os.walk(rootFolder):
    for filename in files:
        foundFile = os.path.join(root, filename)

        if reobj.match(foundFile):
            imgs.append(foundFile)

for img in imgs :
    print 'Checking file: ' + img
    newImg = cleanupString(img) #Code blows up here for some files

任何人都可以为我提供解决此错误的方法吗?我已经尝试添加

# -*- coding: utf-8 -*-

到脚本的顶部,但这没有效果。

谢谢。

4

2 回答 2

6

您的文件名是包含代表 unicode 字符的 UTF-8 字节的字节字符串。HTML 解析器通常使用 unicode 数据而不是字节字符串,特别是当它遇到 & 转义时,因此 Python 会自动尝试为您解码该值,但默认情况下它ASCII用于该解码。这对于 UTF-8 数据失败,因为它包含超出 ASCII 范围的字节。

您需要将字符串显式解码为 un​​icode 对象:

def cleanupString(string):
    string = urllib2.unquote(string).decode('utf8')

    return HTMLParser.HTMLParser().unescape(string)

您的下一个问题将是您现在拥有 unicode 文件名,但是您的文件系统将需要某种编码来处理这些文件名。sys.getfilesystemencoding()您可以使用;检查该编码是什么 用它来重新编码你的文件名:

def cleanupString(string):
    string = urllib2.unquote(string).decode('utf8')

    return HTMLParser.HTMLParser().unescape(string).encode(sys.getfilesystemencoding())

您可以在Unicode HOWTO中了解 Python 如何处理Unicode 。

于 2012-09-27T16:46:41.290 回答
0

看起来你遇到了这个问题。我会尝试颠倒您调用unescapeand的顺序unquote,因为unquote会在您的文件名中添加非 ASCII 字符,尽管这可能无法解决问题。

它窒息的实际文件名是什么?

于 2012-09-27T16:46:00.370 回答