Python os.walk()umlauts u'\ u0308'

时间:2015-11-11 08:55:11

标签: python unicode os.walk

我在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'是变音符号上方的点。

我猜错了一些愚蠢的东西?

2 个答案:

答案 0 :(得分:6)

Unicode字符可以以各种形式表示;有“ö”,但是也有可能使用“o”和单独的组合变音符号来表示相同的字符。 OS X通常更喜欢分离的变体,并且您的编辑器似乎没有优雅地处理它,这两个单独的字符也不匹配您的正则表达式。

如果您需要某种方式或其他方式,则需要规范化您的Unicode数据。见unicodedata.normalize。您需要NFC规范化表格。

答案 1 :(得分:3)

有几个问题:

  1. screenshot@deceze explained归因于Unicode规范化。注意:代码点不必看起来不同,例如,ö(U + 00f6)和ö(U + 006f U + 0308)在我的浏览器中看起来相同

  2. r".*ö.*"是Python 2中的 bytestring ,其值取决于Python源文件顶部的编码声明(类似于:# -*- coding: utf-8 -*-)例如,如果声明的编码是utf-8,则'ö' bytestring是两个字节的序列:'\xc3\xb6'

    正则表达式引擎无法知道应该用于解释输入字节串的实际编码。

    你不应该使用bytestrings来表示文本; 使用Unicode (使用u''文字或在顶部添加from __future__ import unicode_literals

  3. 如果您使用filename.decode('utf8'),则
  4. UnicodeEncodeError会引发os.walk(u"./test"),因为filename已经是Unicode。 Python 2尝试使用filename的默认编码隐式编码'ascii'不解码Unicode :drop .decode('utf-8')

  5. 顺便说一下,Python 3中最后两个问题是不可能的:r".*ö.*"是一个Unicode文字,你不能在那里创建一个带有文字非ascii字符的字节串,而且没有.decode()方法(如果您尝试解码Unicode,则会获得AttributeError)。您可以在Python 3上运行脚本,以检测与Unicode相关的错误。