文件重命名;我能得到一些反馈吗?

时间:2011-03-09 07:11:58

标签: python

背景:我的一位朋友,可能有一些强迫症问题,正在告诉我一个故事,他怎么也不期待他将要投入的工作时间用于重新命名大量的歌曲文件。 An,The,Of和更多资本化。

标准:他给了我一个单词列表,这里省略了,因为你会在代码中看到它们,并告诉我大写是O.K.如果他们是在歌曲的开头,否则他们必须是小写的。

问题1:这实际上是我的第一个脚本,我正在寻找一些反馈。如果有更好的方法来写这个,我希望看到它,以便我可以改进我的编码。该脚本功能齐全,完全符合我的要求。

问题2:最初我没有全部3个功能。我只有替换单词的功能。出于某种原因,它不适用于看起来像这样的文件"月亮的黑暗面#34;。当我运行代码时," Of"将被取代,但"" s都不会被取代。所以,通过反复试验,我发现如果我小写文件的第一个字母,做我的替换功能,最后大写文件,它会工作。任何线索为什么?

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.')

3 个答案:

答案 0 :(得分: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()中看到正在发生的事情,而无需查看功能的详细信息。每个功能都有不同的功能。在仅运行文件系统时,只更改一个文件名,一个实际上重命名文件。

答案 1 :(得分:1)

好的,有些批评:

  • 不要提示参数,从命令行获取它们。它使测试,脚本和许多其他事情变得更加容易。
  • 您所获得的实施无法区分,例如: “剧院”中的“the”
  • 您正在使用当前工作目录来传递您正在处理的目录。不要这样做,只需使用变量。
  • 其他人说,“使用set,它更快”。这个建议是不正确的;正确的建议是“使用set,因为你需要一套”。集合是唯一项目的无序集合(列表是不一定唯一项目的有序集合。)作为使用正确集合的奖励,您的程序可能会运行得更快。
  • 您需要正确地分割您正在尝试的工作。我会解释一下:

您的程序包含两部分:1。您需要遍历某些目录中的所有文件,并根据某些规则重命名它们。 2.规则,给出一个字符串(是的,它将是一个文件名,但忘了那个),大写第一个单词和所有后续单词不在某个给定集合中。

你已经非常轻松,所以进一步深入研究(2)。步骤那里是一个。将一切都归结为小写。湾将字符串分解为单词。 C。对于每个单词,如果你应该将其大写。 d。将单词加入字符串。

写入(2)并编写一个调用它的测试程序以确保它正常工作:

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

当你对(2)感到满意时,写(1)并且整个事情应该有效。

答案 2 :(得分:0)

  1. 使用set代替列表。 (它更快)
  2. 我不确定你在那里做什么。我采取的方法是将整个事物小写,然后将每个单词的第一个字母大写,只要该单词不在集合中,然后将第一个字母大写为大写(以防万一它是特殊字母之一)字)。
  3. 我刚才写的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));
    }
    

    我使用正则表达式而不是在空格上分割,因为我在那里有很多法语单词,而是用's分隔。