我在OSX机器上运行Python 2.7。我正试图在smb上分享一个os.walk。
for root, dirnames, filenames in os.walk("./test"):
for filename in filenames:
print filename
matchObj = re.match( r".*ö.*",filename,re.UNICODE)
如果我使用上面的代码,只要文件名不包含变音符号就可以使用。 在我的shell中,变音符号被打印得很好但是当我将它们复制回utf8格式化的Textdeditor(在我的情况下是Sublime)时,我得到:
screenshot 预期:
filename.jpeg
filename_ö.jpg
当然正则表达式失败了。 如果我硬编码文件名,如:
re.match( r".*ö.*",'filename_ö',re.UNICODE)
它工作正常。
我试过了:
os.walk(u"./test")
filename.decode('utf8')
但是给了我:
return codecs.utf_8_decode(input, errors, True)
UnicodeEncodeError: 'ascii' codec can't encode character u'\u0308' in position 10: ordinal not in range(128)
u'\u0308'
是变音符号上方的点。
我猜错了一些愚蠢的东西?
答案 0 :(得分:6)
Unicode字符可以以各种形式表示;有“ö”,但是也有可能使用“o”和单独的组合变音符号来表示相同的字符。 OS X通常更喜欢分离的变体,并且您的编辑器似乎没有优雅地处理它,这两个单独的字符也不匹配您的正则表达式。
如果您需要某种方式或其他方式,则需要规范化您的Unicode数据。见unicodedata.normalize
。您需要NFC规范化表格。
答案 1 :(得分:3)
有几个问题:
screenshot为@deceze explained归因于Unicode规范化。注意:代码点不必看起来不同,例如,ö(U + 00f6)和ö(U + 006f U + 0308)在我的浏览器中看起来相同
r".*ö.*"
是Python 2中的 bytestring ,其值取决于Python源文件顶部的编码声明(类似于:# -*- coding: utf-8 -*-
)例如,如果声明的编码是utf-8,则'ö'
bytestring是两个字节的序列:'\xc3\xb6'
。
正则表达式引擎无法知道应该用于解释输入字节串的实际编码。
你不应该使用bytestrings来表示文本; 使用Unicode (使用u''
文字或在顶部添加from __future__ import unicode_literals
)
filename.decode('utf8')
,则 UnicodeEncodeError
会引发os.walk(u"./test")
,因为filename
已经是Unicode。 Python 2尝试使用filename
的默认编码隐式编码'ascii'
。 不解码Unicode :drop .decode('utf-8')
顺便说一下,Python 3中最后两个问题是不可能的:r".*ö.*"
是一个Unicode文字,你不能在那里创建一个带有文字非ascii字符的字节串,而且没有.decode()
方法(如果您尝试解码Unicode,则会获得AttributeError
)。您可以在Python 3上运行脚本,以检测与Unicode相关的错误。