2011-03-09 77 views
0

背景:我的一個朋友,他可能會有一些強迫症的問題,告訴我一個故事,他如何不打算將他的工作時間用於重命名大量歌曲文件那裏有An,The,Of和更多的大寫字母。文件重命名;我可以得到一些反饋意見

準則:他給了我一個單詞列表,在這裏省略,因爲你會在代碼中看到它們,並告訴我大寫字母是O.K.如果他們在歌曲的開頭,但是否則他們必須是小寫字母。

問題1:這實際上是我的第一個腳本,我正在尋找一些反饋。如果有更好的方法來寫這個,我想看看它,所以我可以改進我的編碼。該腳本是功能性的,並且正是我想要的。

問題2:最初我沒有全部3個功能。我只有取代單詞的功能。由於某些原因,它不適用於看起來像這個「月球黑暗面」的文件。當我運行代碼時,「Of」將被替換,但「The」將不會被替換。因此,通過試驗和錯誤,我發現如果我小寫了文件的第一個字母,那麼執行我的替換功能,最後輸入大寫的文件,它會起作用。任何線索爲什麼?

import os 
words = ['A','An','The','Of','For','To','By','Or','Is','In','Out','If','Oh','And','On','At'] 
fileList = [] 
rootdir = '' 
#Where are the files? Is the input a valid directory? 
while True: 
    rootdir = raw_input('Where is your itunes library? ') 
    if os.path.isdir(rootdir): break 
    print('That is not a valid directory. Try again.') 
#Get a list of all the files in the directory/sub-directory's 
for root, subFolders, files in os.walk(rootdir): 
    for file in files: 
     fileList.append(os.path.join(root)) 
#Create a function that replaces words. 
def rename(a,b,c): 
    for file in os.listdir(c): 
     if file.find(a): 
      os.rename(file,file.replace(a,b)) 
#Create a function that changes the first letter in a filename to lowercase. 
def renameL(): 
    for file in os.listdir(os.getcwd()): 
     if file.find(' '): 
      os.rename(file,file.replace(file,file[0].lower()+file[1:])) 
#Creat a function that changes the first letter in a filename to uppercase. 
def renameU(): 
    for file in os.listdir(os.getcwd()): 
     if file.find(' '): 
      os.rename(file,file.replace(file,file[0].upper()+file[1:])) 
#Change directory/lowercase the first letter of the filename/replace the offending word/uppercase the first letter of the filename. 
for x in fileList: 
    for y in words:  
     os.chdir(x) 
     renameL()   
     rename(y,y.lower(),x) 
     renameU() 

Exit = raw_input('Press enter to exit.') 
+0

歡迎來到SO。一些筆記。這是精確回答精確問題的地方。所以,背景是不需要的。另外,*請提供反饋/意見*類型的問題更適合http://programmers.stackexchange.com。 – 2011-03-09 07:45:55

+0

感謝您的意見。 – Chris 2011-03-09 08:33:23

回答

0
  1. 使用set,而不是一個列表。 (它更快)
  2. 我不確定你在那裏做什麼。我採取的方法是小寫整個事情,然後大寫每個單詞的第一個字母,只要該單詞不在集合中,然後大寫第一個字母(無論它是哪種特殊話)。

C#版本,我寫了一會兒前:

private static HashSet<string> _small = new HashSet<string>(new[] { "of", "the", "and", "on", "sur", "de", "des", "le", "la", "les", "par", "et", "en", "aux", "d", "l", "s" }); 
static string TitleCase(string str) 
{ 
    if (string.IsNullOrEmpty(str)) return string.Empty; 
    return string.Concat(char.ToUpper(str[0]), 
     Regex.Replace(str, @"\w+", m => 
      { 
       string lower = m.Value.ToLower(); 
       return _small.Contains(lower) 
        ? lower 
        : string.Concat(char.ToUpper(lower[0]), lower.Substring(1)); 
      }) 
      .Substring(1)); 
} 

我用正則表達式,而不是分裂的空間,因爲我有很多的分離,在那裏法語單詞的替代。

+0

他的代碼中有幾個列表,我懷疑一個集合通常比列表更快。那麼,你能詳細說明你的第一點嗎? – 2011-03-09 07:46:55

+0

@ Space_C0wb0y:沒關係,我沒有想到通過。當你在'myset'中做'x'的時候速度會更快,但如果你只是迭代它,它沒有什麼區別。 – mpen 2011-03-10 01:44:08

1

重複的代碼通常被認爲是不好的風格(DRY是流行詞)。另外我通常不嘗試交錯功能。

對於這個小腳本的「設計」,我將首先遍歷目錄並創建一個包含所有音頻文件和目錄的大型列表。然後我編寫一個函數來處理更改列表中的一個項目,並使用map創建另一個列表。現在你有一個current和一個want列表。然後我會zip這些列表一起重新命名。

如果你的音樂庫真的很大,你可以使用itertools,所以你在內存中沒有大的列表,但是迭代器(一次只能在內存中存儲一​​個項目)。這在Python中非常簡單:使用imap而不是mapizip而不是zip

爲了給你一個印象和一些有用的功能提示,這裏是我如何做到這一點的粗略草圖。 (警告:未經測試)

import os 
import sys 

words = ['A','An','The','Of','For','To','By','Or','Is','In','Out','If','Oh','And','On','At'] 
wantWords = map(str.lower, words) 

def main(args): 
    rootdir = args[1] 
    files = findFiles(rootdir) 
    wantFiles = map(cleanFilename, files) 
    rename(files, wantFiles) 

def findFiles(rootdir): 
    result = [] 
    for root, subFolders, files in os.walk(rootdir): 
     for filename in files: 
      result.append(os.path.join(root, filename)) 
    return result 

def cleanFilename(filename): 
    # do replacement magic 

def rename(files, wantFiles): 
    for source, target in zip(files, wantFiles): 
     os.rename(source, target) 

if __name__ == '__main__': 
    main(sys.argv) 

的好處是,你可以在main()看什麼不看入的功能的細節發生。每個功能都做不同的事情。在只走文件系統時,只改變一個文件名,實際上重命名文件。

+0

感謝您的意見。 – Chris 2011-03-09 08:34:39

1

OK,一些批評:

  • 不要提示爲參數,在命令行中得到他們。它使得測試,腳本和其他許多事情變得更加容易。
  • 你得到的實現不會區分,例如「the」from「theatre」
  • 您正在使用current-working-directory傳遞您正在處理的目錄。不要這樣做,只是使用一個變量。
  • 別人說:「使用set,速度更快」。那個建議是不正確的;正確的建議是「使用set,因爲你需要一套」。一組是獨特項目的無序集合(一個列表是不必要唯一項目的有序集合)。作爲使用正確集合的獎勵,您的程序可能運行得更快。
  • 你需要正確地分配你想要做的工作。我會解釋一下:

你的程序有兩個部分:1.你需要遍歷某個目錄中的所有文件,並根據一些規則重命名它們。 2.規則給定一個字符串(是的,這將是一個文件名,但忘記了這一點),大寫第一個單詞和所有後面的單詞不在某些給定的集合。你有(1)下來很好拍,所以深入挖掘(2)。步驟是一個。把所有東西都敲成小寫。灣將字符串分解成單詞。 C。對於每個單詞,如果你應該這樣做,就把它大寫。 d。將單詞加入字符串。

寫(2),並編寫調用它,確保它正常工作的測試程序:

assert capitalizeSongName('the Phantom Of tHe OPERA') == 'The Phantom of the Opera' 

當你快樂(2),寫(1)整個事情應該工作。

+0

我很欣賞這些輸入,並會嘗試弄清楚如何實施您的建議。 – Chris 2011-03-09 08:35:45