【问题标题】:regex and os.walk正则表达式和 os.walk
【发布时间】:2018-08-03 02:34:43
【问题描述】:

我对 python 很陌生,但学得很快。我正在尝试将正则表达式与 os.walk 一起使用来忽略我不想处理的目录。我了解您必须就地修改目录而不是创建新列表。我已经尝试过两种方式。我没有收到任何错误,但它仍然遍历所有目录。排除完整的目录名称可以正常工作。我正在尝试删除名称中带有“EXP”或“-”或“3.2”的所有目录。这是我想忽略的示例 3.2.2.150-20150424.195805_EXP_manuMain_outOfMemFix

这就是我所拥有的:

def runtest(filepath_udu: object) -> object:   
    k = 1
    for root, dirs, files in os.walk(filepath_udu, topdown=True):
        dirs[:] = [item for item in dirs 
                   if item not in ('1node','local','remote')]
        dirs[:] = [dir for dir in dirs 
                   if re.search(r'\bEXP\b', dir) not in dirs \
                   or re.search(r'\b3.2\b', dir) not in dirs \
                   or re.search(r'\w+(?:- \w+)+', dir) not in dirs]
    for file in files:
        do something...

我的第二个目录 [:] 被忽略了,我做错了什么?谢谢

【问题讨论】:

  • if re.search(r'\bEXP\b', dir) not in dirs 检查单词“EXP”是否不在dirs 的列表中。大多数时候,事实并非如此。你想要的是if not re.search(r'\bEXP\b', dir)(原文如此)。与其他两个条件相同,将'or'改为'and'。
  • 附带说明,在括号、方括号或大括号内的表达式中不需要反斜杠继续;这些会自动继续。
  • @DYZ 不,walk 迭代器明确查看您所做的更改。有关详细信息,请参阅the docs,但 OP 完全正确地执行了该部分:“当 topdownTrue 时,调用者可以就地修改 dirnames 列表(可能使用del 或切片赋值),而walk() 只会递归到名称保留在dirnames 中的子目录;这可用于修剪搜索、强加特定的访问顺序或甚至在调用者再次恢复walk() 之前通知walk() 调用者创建或重命名的目录。”
  • 为了澄清一点,我正在遍历产品目录,从固件构建中收集性能数据,以跟踪性能如何变化。我想忽略实验性修复、错误修复、CFI 等以及所有名称中包含 EXP 或“-”的内容。我也不想要像 3.2 这样的旧固件。我想要的固件是 X.X.X.xxx 数字格式,最后一个数字并不总是有 3 位数字——它可以是 1、2 或 3。

标签: python regex directory os.walk


【解决方案1】:

它没有被忽略,只是你的条件总是正确的,所以你没有过滤掉任何东西。

re.search 将返回匹配对象,如果找到,则返回 None,否则。不管怎样,这不会是dirs 的一个元素,因为dirs 只是一个字符串列表。所以你所有的测试都是真的。

不要检查搜索是否在 dirs 中,只需检查它是否真实。 (匹配对象始终为真,None 始终为假。)

另外,在你解决了这个问题之后,我很确定你想保留 所有 测试失败的值——但你使用的是 or 而不是 and,这意味着您将保留 任何 测试失败的值。

所以:

dirs[:] = [dir for dir in dirs
           if not re.search(r'\bEXP\b', dir)
           and not re.search(r'\b3.2\b', dir) 
           and not re.search(r'\w+(?:-\w+)+', dir)]

或者,如果反过来更容易理解——不要保留所有测试失败的所有值,而是保留所有测试都不为真的值:

dirs[:] = [dir for dir in dirs if not (
           re.search(r'\bEXP\b', dir) or
           re.search(r'\b3.2\b', dir) or
           re.search(r'\w+(?:-\w+)+', dir))]

【讨论】:

  • 这成功了!非常感谢。不过,我确实必须做一个小改动。使用 r\bEXP\b 不起作用。我将其更改为正则表达式 (r'\w+(?:EXP\w+)+' 并且这有效,尽管一位同事表示如果我删除了本来可以工作的 \b。
  • @DB_65 我根本没有测试你的正则表达式;我只是假设他们做了你想要的,你只需要知道如何正确地应用它们。很高兴知道您成功了。
【解决方案2】:

除了使用os.walk,您可以通过在排除与您的排除条件匹配的子目录后使用os.scandir 自行递归遍历子目录来避免处理列表操作的开销:

def runtest(filepath_udu: object) -> object:
    for entry in os.scandir(filepath_udu):
        if entry.is_dir() and entry.name not in ('1node', 'local', 'remote') and not re.search(r'\bEXP\b', entry.name) and not re.search(r'\b3.2\b', entry.name) and not re.search(r'\w+(?:- \w+)+', entry.name):
            runtest(entry.path)
        else:
            do something ...

【讨论】:

  • 什么开销?所有这些额外的stat 系统调用(在每个文件上调用isdir)的成本将远远高于避免列表理解所节省的成本。
  • 谢谢。我已经用更有效的os.scandir 更新了我的答案,这是os.walk 在内部使用的。 OP详情可参考PEP 471
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-29
  • 1970-01-01
  • 1970-01-01
  • 2017-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多