【问题标题】:Python findall, regex, unicodePython findall、正则表达式、unicode
【发布时间】:2015-02-06 12:32:35
【问题描述】:

我正在尝试编写一个 Python 脚本,该脚本通过目录树搜索并列出所有 .flac 文件并从相应的导出 Arist、Album 和 Title。 dir/subdir/filename 并将其写入文件。该代码工作正常,直到它遇到一个 unicode 字符。代码如下:

import os, glob, re

def scandirs(path):
    for currentFile in glob.glob(os.path.join(path, '*')):
    if os.path.isdir(currentFile):
        scandirs(currentFile)
    if os.path.splitext(currentFile)[1] == ".flac":
        rpath = os.path.relpath(currentFile)
        print "**DEBUG** rpath =", rpath
        title = os.path.basename(currentFile)
        title = re.findall(u'\d\d\s(.*).flac', title, re.U)
        title = title[0].decode("utf8")
        print "**DEBUG** title =", title
        fpath = os.path.split(os.path.dirname(currentFile))
        artist = fpath[0][2:]
        print "**DEBUG** artist =", artist
        album = fpath[1]
        print "**DEBUG** album =", album
        out = "%s | %s | %s | %s\n" % (rpath, artist, album, title)
        flist = open('filelist.tmp', 'a')
        flist.write(out)
        flist.close()

scandirs('./')

代码输出:

**DEBUG** rpath = Thriftworks/Fader/Thriftworks - Fader - 01 180°.flac
**DEBUG** title = 180°
**DEBUG** artist = Thriftworks
**DEBUG** album = Fader
Traceback (most recent call last):
  File "decflac.py", line 25, in <module>
    scandirs('./')
  File "decflac.py", line 7, in scandirs
    scandirs(currentFile)
  File "decflac.py", line 7, in scandirs
    scandirs(currentFile)
  File "decflac.py", line 20, in scandirs
    out = "%s | %s | %s | %s\n" % (rpath, artist, album, title)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 46: ordinal not in range(128)

但是当在 Python 控制台中尝试时,它工作正常:

>>> import re
>>> title = "Thriftworks - Fader - 01 180°.flac"
>>> title2 = "dummy"
>>> title = re.findall(u'\d\d\s(.*).flac', title, re.U)
>>> title = title[0].decode("utf8")
>>> out = "%s | %s\n" % (title2, title)
>>> print out
dummy | 180°

所以,我的问题: 1)为什么相同的代码在控制台中有效,但在脚本中无效? 2) 如何修复脚本?

【问题讨论】:

    标签: python regex unicode findall


    【解决方案1】:

    glob 与包含Unicode 字符的文件名一起使用时,请使用Unicode 字符串作为模式。这使得 glob 返回 Unicode 字符串而不是字节字符串。打印 Unicode 字符串会在输出时自动将它们编码为控制台的编码。如果您的歌曲包含控制台编码不支持的字符,您仍然会遇到问题。在这种情况下,将数据写入 UTF-8 编码文件并在支持 UTF-8 的编辑器中查看。

    >>> import glob
    >>> for f in glob.glob('*'): print f
    ...
    ThriftworksFaderThriftworks - Fader - 01 180░.flac
    >>> for f in glob.glob(u'*'): print f
    ...
    ThriftworksFaderThriftworks - Fader - 01 180°.flac
    

    这也适用于os.walk,并且是一种更简单的递归搜索方式:

    #!python2
    import os, fnmatch
    
    def scandirs(path):
        for path,dirs,files in os.walk(path):
            for f in files:
                if fnmatch.fnmatch(f,u'*.flac'):
                    album,artist,tracktitle = f.split(u' - ')
                    print 'Album: ',album
                    print 'Artist:',artist
                    title,track = tracktitle.split(u' ',1)
                    track = track[:-5]
                    print 'Track: ',track
                    print 'Title: ',title
    
    scandirs(u'.')
    

    输出:

    Album:  ThriftworksFaderThriftworks
    Artist: Fader
    Track:  180°
    Title:  01
    

    【讨论】:

    • 谢谢你,马克。仍然无法让它与带有 u 的 glob 前缀一起工作,但是使用 os.walk 而不是 glob 构造,该脚本在 unicode 和 Python2 上工作得很好。
    【解决方案2】:

    Python 控制台可与您的终端配合使用,并根据其语言环境解释 unicode 编码。

    用新的str.format替换该行:

    out = u"{} | {} | {} | {}\n".format(rpath, artist, album, title)
    

    写入文件时编码为utf8:

    with open('filelist.tmp', 'a') as f:
        f.write(out.encode('utf8'))
    

    或者import codecs直接做:

    with codecs.open('filelist.tmp', 'a', encoding='utf8') as f:
        f.write(out)
    

    或者,因为 utf8 是默认的:

    with open('filelist.tmp', 'a') as f:
        f.write(out)
    

    【讨论】:

    • 感谢您对控制台和语言环境的回复和解释。不幸的是,提议的代码修复似乎不起作用;当以 'u' 为 'out' 的值添加前缀时,脚本会因相同的错误而停止。我唯一可以让它通过'out ='的时间是在评论'title = title [0] .decode(“utf8”)'行而不是'out'前缀'u'时。但随后脚本在 write 语句中出错了;同样的错误。
    • * 我尝试了所有三个建议的写语句
    【解决方案3】:
    1. 在控制台中,您的终端设置定义了编码。如今,这主要是unices上的Unicode,例如Windows 上的 Linux/BSD/MacOS 和 Windows-1252。在解释器中,默认为python文件的编码,通常是ascii(除非你的代码以UTF Byte-Order-Mark开头)。

    2. 我不完全确定,但也许在字符串 "%s | %s | %s | %s\n" 前加上 u 以使其成为 unicode 字符串可能会有所帮助。

    【讨论】:

    • 感谢您对控制台和解释器之间的差异的解释。完全有道理。不幸的是,建议的 u 前缀不起作用,请参阅我的回复 eumiro 的帖子。
    【解决方案4】:

    通过切换到 Python3 来解决,它可以按预期处理 unicode 情况。
    替换:

    title = title[0].decode("utf8")
    

    为:

    title = title[0]
    

    甚至不需要在 'out' 的值前面加上 'u' 或在写入时指定编码。
    我喜欢 Python3。

    【讨论】:

      猜你喜欢
      • 2015-08-13
      • 2011-12-06
      • 1970-01-01
      • 1970-01-01
      • 2011-07-18
      • 2013-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多