Python os.walk() 元音变音 u'\u0308'

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

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

我猜我忽略了一些愚蠢的事情?

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

如果您特别需要一种方式,则需要规范化您的 Unicode 数据。参见 unicodedata.normalize。您需要 NFC 规范化形式。

有几个问题:

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

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

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

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

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

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