加入文件名时出现UnicodeEncodeError

时间:2010-01-05 04:20:05

标签: python unicode filenames

在执行以下代码时抛出“UnicodeDecodeError:'ascii'编解码器无法解码位置2中的字节0xc2:序号不在范围内(128)”:

filename = 'Spywaj.ttf'
print repr(filename)
>> 'Sp\xc2\x88ywaj.ttf'
filepath = os.path.join('/dirname', filename)

但该文件有效且存在于磁盘上。文件名是从“unzip -l”命令中提取的。如何加入像这样的文件名?

操作系统和文件系统

Filesystem: ext3    relatime,errors=remount-ro 0       0
Locale: en_US.UTF-8

Alex的建议 os.path.join现在正常工作,但我仍然无法使用它加入的文件名访问磁盘上的文件。

filename = filename.decode('utf-8')
filepath = os.path.join('/dirname', filename)
print filepath
>> /dirname/u'Sp\xc2\x88ywaj.ttf'
print os.path.isfile(filepath)
>> False

new_filepath = filepath.encode('Latin-1').encode('utf-8')
print new_filepath
>> /dirname/u'Sp\xc2\x88ywaj.ttf'
print type(filepath)
>> <type 'unicode'>
print os.path.isfile(new_filepath)
>> False

valid_filepath = glob.glob('/dirname/*.ttf')[0]
print valid_filepath
>> /dirname/Spywaj.ttf (SO cannot display the chars in filename)
print type(valid_filepath)
>> <type 'str'>
print os.path.isfile(valid_filepath)
>> True

4 个答案:

答案 0 :(得分:8)

在Latin-1(ISO-8859-1)和Windows-1252中,0xc2将是具有回音重音的大写字母A ...似乎不会出现在您显示的代码中的任何位置!你能加一个

吗?
print repr(filename)
os.path.join调用之前

(并且还将'/dirname'放入变量并打印其repr以获得完整性?)。我想也许那个流浪的角色 那里,但是由于某些原因你没有看到它 - repr会揭示它。

如果你的文件名中有一个Latin-1(或Win-1252)非Ascii字符,你必须使用Unicode - 和/或根据你的操作系统和文件系统,使用一些特定的编码。

编辑:由于repr,OP确认实际上两个字节不可能是ASCII - 0xc2然后是0x88,对应于OP认为是一个小写L. 好吧,那个序列将是一个带有插入符号(代码点0x88)的Unicode大写字母A,在刚刚流行的 UTF-8 编码中 - 对于OP乞丐的解释,它看起来像小写字母L,但我想<一些字体可能在图形上疯狂,足以造成这种混乱。

所以我首先尝试filename = filename.decode('utf-8') - 这应该允许os.path.join工作。如果open然后对生成的Unicode字符串进行调整(它可能有效,具体取决于文件系统和操作系统),则下一次尝试是尝试使用该Unicode对象的.encode('Latin-1').encode('utf-8')。如果所有编码都不起作用,那么我认为OP尚未提供的操作系统和文件系统的信息变得至关重要。

答案 1 :(得分:6)

我通过将这些行添加到/etc/apache2/envvars并重新启动Apache来修复了UnicodeDecodeError。

export LANG='en_US.UTF-8'
export LC_ALL='en_US.UTF-8'

如下所述: https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/modwsgi/#if-you-get-a-unicodeencodeerror

我花了一些时间来调试它。

答案 2 :(得分:2)

filename = filename.decode('utf-8').encode("latin-1")

适用于我Splywaj.zip

的文件
>>> os.path.isfile(filename.decode("utf8").encode("latin-1"))
True
>>>

答案 3 :(得分:0)

证据问题1 ###

  

在执行以下代码时抛出“UnicodeDecodeError:'ascii'编解码器无法解码位置2中的字节0xc2:序号不在范围内(128)”:

filename = 'Spywaj.ttf'
print repr(filename)
>> 'Sp\xc2\x88ywaj.ttf'
filepath = os.path.join('/dirname', filename)

我无法看到如何获得该异常 - os.path.join的两个args都是str对象。没有理由尝试将任何东西转换为unicode。您确定上面的代码与您的运行完全一致吗?

证据问题2

  

Alex的建议os.path.join现在可以正常工作,但我仍然无法使用它加入的文件名访问磁盘上的文件。

filename = filename.decode('utf-8')
filepath = os.path.join('/dirname', filename)
print filepath
>> /dirname/u'Sp\xc2\x88ywaj.ttf'

抱歉,假设filename没有从上一个代码段改变,那肯定是不可能的。它看起来像os.path.join('/dirname', repr(filename))的结果......请确保您发布实际运行的代码以及实际输出(以及实际的回溯,如果有的话)。

混乱

new_filepath = filepath.encode('Latin-1').encode('utf-8')

亚历克斯意味着尝试两次,每次都使用其中一种编码 - 两次编码都不要尝试一次!由于filepath中的所有字符都在ASCII范围内(参见证据问题2),效果只是filepath.encode('ascii')

简单解决方案

您知道如何找到您感兴趣的文件的名称:

valid_filepath = glob.glob('/dirname/*.ttf')[0]

如果您必须在脚本中对该名称进行硬编码,则可以使用repr()函数来获取可以在脚本中键入的表示形式,而无需担心utf8,unicode,编码,解码和所有噪声:< / p>

print repr(valid_filepath)

我们假设它打印'/dirname/Sp\xc2\x88ywaj.ttf' ...然后您需要做的就是仔细复制并将其粘贴到您的脚本中:

file_path = '/dirname/Sp\xc2\x88ywaj.ttf'