【问题标题】:AttributeError: 'NoneType' object has no attribute 'group' while using re.match for renaming of file namesAttributeError:“NoneType”对象在使用 re.match 重命名文件名时没有属性“组”
【发布时间】:2017-11-10 07:38:37
【问题描述】:

我正在尝试使用 windows 上的 pyhton 重命名文件夹中所有以相同字符串 (Vertragshandbuch_Beitrag_) 开头的一些文件。

一个示例文件名: Vertragshandbuch_Beitrag_004_Term Sheet.docx

新文件名应如下所示:4.docx

我当前的代码如下所示:

import os
import re

for filename in os.listdir("."):
    m = re.match("Vertragshandbuch_Beitrag_(\d+)_(\w+(\W\w+)*)\.docx", filename)    
    number = m.group(1)  
    new_filename = number + ".docx"
    os.rename(filename, new_filename)
    print(new_filename)

我收到此错误: 回溯(最近一次通话最后): 文件“C:(...)rename.py”,第 6 行,在 数字 = m.group(1) AttributeError:“NoneType”对象没有属性“组”

我在这里用几个文件名检查了正则表达式:https://regex101.com/,它总是完美匹配。

我是 python 新手,在问这个问题之前我搜索了很长时间,所有关于规范化文件名的提示都没有帮助。

我将输入后的脚本从 blurp 更改为:

import os
import re

for filename in os.listdir("."):
    m = re.match(r'Vertragshandbuch_Beitrag_(\d+)_(\w+(\W\w+)*)\.docx', filename)    
    number = m.group(1)  
    new_filename = number + ".docx"
    os.rename(filename, new_filename)
    print(new_filename)

当我检查正则表达式时仍然是相同的错误并且仍然匹配。

测试我现在使用的正则表达式匹配:

import os
import re

for filename in os.listdir("."):
    m = re.match(r'Vertragshandbuch_Beitrag_(\d+)_(\w+(\W\w+)*)\.docx', filename)  
    number = m.group(1)  
    new_filename = number + ".docx"
    if m is not None:
        os.rename(filename, new_filename)
        print(new_filename)

还是一样的错误信息。

好的,作为最后的手段,我在一个只包含文件 Vertragshandbuch_Beitrag_003_Letter.docx 的文件夹中尝试了这个:

import os, sys
import re

for filename in os.listdir("."):
    m = re.match(r"Vertragshandbuch_Beitrag_(\d+)_(\w+(\W\w+)*)\.docx", filename)    
    print(m)

我得到以下结果: <_sre.sre_match span="(0," match="Vertragshandbuch_Beitrag_003_Letter.docx">

看起来是匹配的,但仍然是错误。

【问题讨论】:

  • re.match() 在您的正则表达式不匹配时返回None。您可以通过if m is not None 进行检查。此外,您需要在正则表达式模式前加上r 前缀,例如r"xyz",否则\d 之类的东西将不起作用。有关详细信息,请参阅re docs
  • 我将您的正则表达式(r'' 版本)和示例文件名复制到一个小脚本中,它对我有用。目录中的所有文件是否都与模式匹配?如果没有,您必须检查None
  • 我也在尝试插入 None 测试,但我总是会得到无效的语法。我试过了:
  • if m is not None os.rename(filename, new_filename) print(new_filename)
  • None后面好像少了一个冒号。

标签: python regex


【解决方案1】:

当您调用re.match() 时,如果提供的字符串与正则表达式模式不匹配,它将等于None

我假设问题是,您遇到的文件名与您提供的正则表达式模式不匹配。

即使正则表达式正确匹配您的文件,re.match() 第一次返回None 也会中断,除非您明确捕获它。否则,当您调用re.match().group() 时,它不存在并引发错误。

当我制作具有指定名称格式的文件时,这对我有用:

import os
import re

def rename_num(path):

    # Create a pattern to match filenames to
    match_pattern = r"Vertragshandbuch_Beitrag_(\d+)_(\w+(\W\w+)*)\.docx"
    pattern = re.compile(match_pattern)


    # For each file in the path supplied above
    for filename in os.listdir(path):

        # Use the re module to match the regex pattern to the filename.
        # If the filename doesn't match the regex found will be equal to None.
        found = pattern.match(filename)

        # If found is not equal to None, print the filename, groups and rename the file
        if found:

            os.rename(os.path.join(path, filename), os.path.join(path, found.group(1) + ".docx"))

            print("{} renamed to {}".format(filename, found.group(1) + ".docx"))



# To run the above method in the directory the script is in:
p = os.path.abspath(os.path.dirname(__file__))
rename_num(p)

我创建的文件名称与您提供的一样(数字 001 - 007)和

这是我的输出:

Vertragshandbuch_Beitrag_001_Term Sheet.docx renamed to 001.docx
Vertragshandbuch_Beitrag_002_Term Sheet.docx renamed to 002.docx
Vertragshandbuch_Beitrag_003_Term Sheet.docx renamed to 003.docx
Vertragshandbuch_Beitrag_004_Term Sheet.docx renamed to 004.docx
Vertragshandbuch_Beitrag_005_Term Sheet.docx renamed to 005.docx
Vertragshandbuch_Beitrag_006_Term Sheet.docx renamed to 006.docx
Vertragshandbuch_Beitrag_007_Term Sheet.docx renamed to 007.docx

我希望这会有所帮助。

【讨论】:

  • 非常感谢杰比。现在首先在 test 文件夹中使用以前无法使用的单个文件,而不是在对正则表达式进行更多更改以获得其中带有“-”的名称之后在整个文件夹中使用。一定是 re.compile 成功了。谢谢!
  • 没问题。如果此答案对您有所帮助,请接受它作为解决方案。
  • @rena re.compile() 对模式是否匹配没有任何影响。
  • 这是正确的。 re.compile() 只是比re.match() 有速度改进,因此在一次将模式与多个字符串匹配时是首选。 (就像在 for 循环中一样)。应该提到这一点。谢谢@Blurp
  • 另外,请注意,当使用re.match()re.search() 等函数时,模式将被自动编译和缓存(docs)。
【解决方案2】:

如果您愿意,也可以将匹配项设为可选。这样,即使你的字符串不匹配,你也会得到一个匹配对象(不是None)。

把它放在首位,因为它非常重要:.* 和类似的 将运行可选匹配,因此如果您不这样做,这将不起作用 知道您要捕获的子字符串周围可能是什么。

话虽如此,这是通常的行为。

>>> re.match('(a)', a).groups()
('a',)

>>> re.match('(a)', b).groups()
AttributeError: 'NoneType' object has no attribute 'groups'

括号后的? 使得匹配'a' 是可选的。

>>> re.match('(a)?', 'a').groups()
('a',)

>>> re.match('(a)?', 'b').groups()
(None,)

您甚至可以将默认值传递给groups

re.match('(a)?', 'a').groups('cannot find a')
('a',)

re.match('(a)?', 'b').groups('cannot find a')
('cannot find a',)

这有时可以使代码更具可读性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-12
    • 1970-01-01
    • 2022-06-30
    • 1970-01-01
    相关资源
    最近更新 更多