使用Python,我试图根据每个给定文本文件中的特定短语重命名目录中的一系列.txt文件。换句话说,更具体地说,我有几百个具有任意名称的文本文件,但在每个文件中都是一个独特的短语(类似于No. 85-2156)。我想用每个文本文件的给定短语替换任意文件名。这个短语并不总是在同一条线上(虽然它没有那么大的偏差),但它总是采用相同的格式并带有前缀。
我看了os module,我明白了
可能有用,但我不明白如何将这些函数与诸如linecache之类的intratext操作函数或一般行读取函数相结合。
我已经想过通过多种方式完成这项任务,但似乎最简单,最有效的方法是创建一个循环,在文件中找到唯一的短语,将其分配给变量并使用该变量重命名移动到下一个文件之前的文件。
这看起来应该很容易,所以我觉得写这个问题很傻。我花了最后几个小时看阅读文档并通过StackOverflow进行解析,但似乎以前没有人遇到过这个问题 - 或者至少他们没有问过他们的问题。
有人能指出我正确的方向吗?
编辑1:当我使用this website创建正则表达式模式时,它会创建笨重但看似可行的代码:
import re
txt='No. 09-1159'
re1='(No)' # Word 1
re2='(\\.)' # Any Single Character 1
re3='( )' # White Space 1
re4='(\\d)' # Any Single Digit 1
re5='(\\d)' # Any Single Digit 2
re6='(-)' # Any Single Character 2
re7='(\\d)' # Any Single Digit 3
re8='(\\d)' # Any Single Digit 4
re9='(\\d)' # Any Single Digit 5
re10='(\\d)' # Any Single Digit 6
rg = re.compile(re1+re2+re3+re4+re5+re6+re7+re8+re9+re10,re.IGNORECASE|re.DOTALL)
m = rg.search(txt)
name = m.group(0)
print name
当我操纵它以适应glob.glob
结构时,并按照这样做:
import glob
import os
import re
re1='(No)' # Word 1
re2='(\\.)' # Any Single Character 1
re3='( )' # White Space 1
re4='(\\d)' # Any Single Digit 1
re5='(\\d)' # Any Single Digit 2
re6='(-)' # Any Single Character 2
re7='(\\d)' # Any Single Digit 3
re8='(\\d)' # Any Single Digit 4
re9='(\\d)' # Any Single Digit 5
re10='(\\d)' # Any Single Digit 6
rg = re.compile(re1+re2+re3+re4+re5+re6+re7+re8+re9+re10,re.IGNORECASE|re.DOTALL)
for fname in glob.glob("\file\structure\here\*.txt"):
with open(fname) as f:
contents = f.read()
tname = rg.search(contents)
print tname
然后打印出模式的字节位置 - 表示正则表达式模式是正确的。但是,当我在原始nname = tname.group(0)
之后添加tname = rg.search(contents)
行并更改print函数以反映更改时,它会给出以下错误:AttributeError:'NoneType'对象没有属性'group ”。当我尝试复制并粘贴@ joaquin的代码行时,它出现了同样的错误。我打算将此作为对@spatz答案的评论发布,但我希望包含这么多代码,这似乎是表达“新”问题的更好方法。感谢大家的帮助。
编辑2:这是针对下面的@joaquin答案:
import glob
import os
import re
for fname in glob.glob("/directory/structure/here/*.txt"):
with open(fname) as f:
contents = f.read()
tname = re.search('No\. (\d\d\-\d\d\d\d)', contents)
nname = tname.group(1)
print nname
上次编辑:我主要使用编写的代码来使用它。发生的事情是有一些文件没有那个正则表达式,所以我认为Python会跳过它们。傻我。所以我花了三天时间学习编写两行代码(我知道课程不止于此)。我也使用了这里推荐的错误捕获方法。我希望我可以检查你们所有人的答案,但我最为困扰@Joaquin,所以我把它给了他。这是一次很棒的学习经历。谢谢大家对你的时间如此慷慨。最终的代码如下。
import os
import re
pat3 = "No\. (\d\d-\d\d)"
ext = '.txt'
mydir = '/directory/files/here'
for arch in os.listdir(mydir):
archpath = os.path.join(mydir, arch)
with open(archpath) as f:
txt = f.read()
s = re.search(pat3, txt)
if s is None:
continue
name = s.group(1)
newpath = os.path.join(mydir, name)
if not os.path.exists(newpath):
os.rename(archpath, newpath + ext)
else:
print '{} already exists, passing'.format(newpath)
答案 0 :(得分:3)
我没有为您提供一些您只需复制粘贴而无需理解的代码,而是希望引导您完成解决方案,以便您能够自己编写,更重要的是获得足够的知识以便能够下次单独做。
执行所需操作的代码由三个主要部分组成:
最好使用glob模块实现。此模块允许您指定类似shell的通配符,它将扩展它们。这意味着,为了获取给定目录中的.txt
文件列表,您需要调用函数glob.iglob("/path/to/directory/*.txt")
并迭代其结果(for filename in ...:
)。
获得文件名后,我们需要open()
,使用read()
读取其内容并将其存储在我们可以搜索所需内容的变量中。这看起来像这样:
with open(filename) as f:
contents = f.read()
现在我们有了内容,我们需要寻找独特的短语。这可以使用regular expressions完成。将所需的新文件名存储在变量中,例如newfilename
。
现在我们同时拥有旧文件名和新文件名,我们只需要重命名该文件,并使用os.rename(filename, newfilename)
完成。
如果要将文件移动到其他目录,请使用os.rename(filename, os.path.join("/path/to/new/dir", newfilename)
。请注意,我们需要os.path.join
来使用目录路径和newfilename
构建文件的新路径。
答案 1 :(得分:2)
没有检查或保护失败(检查archpath是一个文件,如果newpath已存在,如果搜索成功等等),但这应该有效:
import os
import re
pat = "No\. (\d\d\-\d\d\d\d)"
mydir = 'mydir'
for arch in os.listdir(mydir):
archpath = os.path.join(mydir, arch)
with open(archpath) as f:
txt = f.read()
s = re.search(pat, txt)
name = s.group(1)
newpath = os.path.join(mydir, name)
os.rename(archpath, newpath)
修改:我测试了正则表达式以显示其工作原理:
>>> import re
>>> pat = "No\. (\d\d\-\d\d\d\d)"
>>> txt='nothing here or whatever No. 09-1159 you want, does not matter'
>>> s = re.search(pat, txt)
>>> s.group(1)
'09-1159'
>>>
正则表达式非常简单:
\. -> a dot
\d -> a decimal digit
\- -> a dash
所以,它说:搜索字符串"No. "
,然后搜索由破折号分隔的2 + 4个十进制数字。
括号是创建一个我可以使用s.group(1)
恢复的组,其中包含代码编号。
这就是你得到的,之前和之后:
文件文件one.txt,two.txt和three.txt始终相同,只有数字更改:
this is the first
file with a number
nothing here or whatever No. 09-1159 you want, does not matter
the number is
答案 2 :(得分:1)
创建文件备份,然后尝试以下操作:
import glob
import os
def your_function_to_dig_out_filename(lines):
import re
# i'll let you attempt this yourself
for fn in glob.glob('/path/to/your/dir/*.txt'):
with open(fn) as f:
spam = f.readlines()
new_fn = your_function_to_dig_out_filename(spam)
if not os.path.exists(new_fn):
os.rename(fn, new_fn)
else:
print '{} already exists, passing'.format(new_fn)