2015-02-06 78 views
1

我試圖編寫一個Python腳本,通過目錄樹進行搜索並列出所有.flac文件並從resp中派生Arist,Album和Title。 dir/subdir /文件名並將其寫入文件。該代碼工作正常,直到它擊中一個Unicode字符。下面的代碼:python findall,正則表達式,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)如何修復腳本?

回答

0

當使用帶有包含Unicode字符的文件名的glob時,請使用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'.') 

輸出:

​​
+0

謝謝,馬克。仍然無法讓它與u前綴glob一起工作,但是使用os.walk而不是glob構造,腳本在unicode和Python2中工作得很好。 – 2015-02-09 12:25:48

0

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) 
+0

謝謝您的答覆,並說明有關控制檯和語言環境。不幸的是,提出的代碼修復似乎不起作用;當用'u'爲'out'的值加上前綴時,腳本將以相同的錯誤停止。唯一一次我可以讓它通過'out ='的時候是在註釋'title = title [0] .decode(「utf8」)'行而不是用'u'前綴'out'時。但後來這個劇本在寫作聲明中變得cra亮起來。同樣的錯誤。 – 2015-02-06 22:23:14

+0

*我嘗試了全部三條建議書寫聲明 – 2015-02-06 22:31:50

0
  1. 在控制檯中,您的終端設置定義了編碼。現在,這主要是Unicode的統一,例如, Windows上的Linux/BSD/MacOS和Windows-1252。在解釋器中,它默認爲python文件的編碼,通常是ascii(除非您的代碼以UTF Byte-Order-Mark開頭)。

  2. 我並不完全確定,但可能在字符串「%s |%s |%s |%s \ n」前面加上u以使其成爲unicode字符串可能有所幫助。

+0

感謝您對控制檯和解釋器之間差異的解釋。總體感覺。不幸的是,建議的u前綴不起作用,請參閱我的回覆eumiro的帖子。 – 2015-02-06 22:29:56

0

通過切換到Python3解決,該Python3按預期處理unicode情況。
替補:

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

爲:

title = title[0] 

甚至沒有需要的 '出' 與 'U' 前綴值或寫指定的編碼。
我愛Python3。