Python 根据文件内容重命名文件

Python 根据文件内容重命名文件,python,Python,使用Python,我试图根据每个给定文本文件中的特定短语重命名目录中的一系列.txt文件。换句话说,更具体地说,我有几百个任意名称的文本文件,但每个文件中都有一个独特的短语(如No.85-2156)。对于每个文本文件,我想用给定的短语替换任意文件名。这个短语并不总是在同一行上(虽然它没有太大的偏离),但它总是以相同的格式出现,并且带有No.前缀 我已经看过了,我明白了怎么做 可能很有用,但我不知道如何将这些函数与文本内操作函数(如或一般的行读取函数)结合起来 我想了很多方法来完成这项任

使用Python,我试图根据每个给定文本文件中的特定短语重命名目录中的一系列.txt文件。换句话说,更具体地说,我有几百个任意名称的文本文件,但每个文件中都有一个独特的短语(如No.85-2156)。对于每个文本文件,我想用给定的短语替换任意文件名。这个短语并不总是在同一行上(虽然它没有太大的偏离),但它总是以相同的格式出现,并且带有No.前缀

我已经看过了,我明白了怎么做

可能很有用,但我不知道如何将这些函数与文本内操作函数(如或一般的行读取函数)结合起来


我想了很多方法来完成这项任务,但似乎最简单、最有效的方法是创建一个循环,在文件中找到唯一的短语,将其分配给一个变量,并在移动到下一个文件之前使用该变量重命名文件

这似乎应该很容易,以至于我觉得写这个问题很傻。在过去的几个小时里,我一直在通过StackOverflow阅读文档和解析,但似乎以前没有人遇到过这个问题——或者至少他们没有问过自己的问题

谁能给我指出正确的方向吗

编辑1:当我使用创建正则表达式模式时,它创建了庞大但似乎可行的代码:

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
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)
with open(filename) as f:
    contents = f.read()
然后打印出模式的字节位置——表示正则表达式模式是正确的。但是,当我在原始
tname=rg.search(contents)
之后添加
nname=tname.group(0)
行,并围绕打印函数进行更改以反映更改时,它会给我以下错误: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)

创建文件备份,然后尝试以下操作:

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
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)
with open(filename) as f:
    contents = f.read()

没有对故障进行检查或保护(检查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

我不想为您提供一些代码,您只需在不理解的情况下复制粘贴即可,我想让您了解解决方案,这样您就可以自己编写,更重要的是,您可以获得足够的知识,以便下次能够独自完成

实现您所需功能的代码由三个主要部分组成:

  • 获取需要迭代的所有文件名的列表
  • 对于每个文件,提取生成文件新名称所需的信息
  • 将文件的旧名称重命名为刚生成的新名称
  • 获取文件名列表 这最好通过模块实现。此模块允许您指定类似shell的通配符,并将其展开。这意味着,为了获得给定目录中
    .txt
    文件的列表,您需要调用函数
    glob.iglob(“/path/to/directory/*.txt”)
    ,并迭代其结果(
    中的文件名:

    生成新名称 一旦我们有了文件名,我们需要
    打开()
    它,使用
    read()
    读取它的内容,并将它存储在一个变量中,在这个变量中我们可以搜索我们需要的内容。看起来是这样的:

    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
    
    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)
    
    with open(filename) as f:
        contents = f.read()
    
    现在我们有了内容,我们需要寻找独特的短语。这可以通过使用。将所需的新文件名存储在变量中,例如
    newfilename

    改名 既然我们有了旧的和新的文件名,我们只需要重命名文件,这是使用
    os.rename(filename,newfilename)
    完成的


    如果要将文件移动到其他目录,请使用
    os.rename(文件名,os.path.join(“/path/to/new/dir”,newfilename)
    。注意,我们需要
    os.path。在这里加入
    ,使用目录路径和
    newfilename

    为文件创建一个备份,只需尝试一下,看看是否遇到了问题。目前,您的想法似乎完全正确。只需开始一步一步地实施它。“看起来最简单、最有效的方法是创建一个循环,在文件中找到唯一的短语,将其分配给一个变量,并在移动到下一个文件之前使用该变量重命名该文件。”还有。你的问题是什么?听起来非常合理