【问题标题】:How to use re to search for items in one list inside another list in Python如何使用 re 在 Python 中的另一个列表中搜索一个列表中的项目
【发布时间】:2009-12-09 06:38:55
【问题描述】:

我正在阅读一个字符串列表,每个字符串都与一个文件名相关。但是,每个字符串都减去扩展名。我想出了以下代码:

import re
item_list = ['item1', 'item2']
search_list = ['item1.exe', 'item2.pdf']
matches = []
for item in item_list:
    # Match item in search_list using re - I assume this is the best way to do this
    regex = re.compile("^"+item+"\.")
    for file in search_list:
        if regex.match(file):
            matches.append((item, file))

至于重复匹配,我并不担心两个文件被命名为“foo.bar”和“foo.foo.bar”。话虽如此,有没有更好的方法呢?

谢谢。

【问题讨论】:

  • 有助于了解两个列表各有多少项,以及调用代码的频率。
  • @Will,我会说列表中有数千个文件。该列表应该比目录中的实际文件数略大(5% 左右)。

标签: python regex


【解决方案1】:

您可以像这样将所有项目组合成一个正则表达式,这样会更有效

import re
item_list = ['item1', 'item2']
regex = re.compile("^("+"|".join(item_list)+")\.")
search_list = ['item1.exe', 'item2.pdf']
matches = []
for file in search_list:
    match = regex.match(file)
    if match:
        matches.append((match.group(1), file))

更好的解决方案可能是使用 os.path 函数解析文件名,但解析出基本名称并在集合中查找它们。

【讨论】:

  • 如果项目可以包含像.这样的正则表达式特殊标点符号,您需要在加入之前re.escapeitem_list中的每个项目。
  • 谢谢尼克,这篇文章值得一百票有用!找到 timeit 模块并根据我的原始算法、Dave Kirby 的算法和你的算法运行测试。结果如下: alex_k : 15.93 dave_kirby : 6.98 nick_craig_wood : 0.24
【解决方案2】:

使用 splitext 获取不带扩展名的文件名:

import os.path

for item in item_list:
    for filename in search_list:
        if item == os.path.splitext(filename)[0]:
            matches.append((item, file))

这样更正确,但通过阅读代码也更容易理解您的意图。或者,如果您想允许 foo 匹配 foo.bar.txt 则使用 filename.startswith(item + '.') 代替。

【讨论】:

  • +1 用于拆分文本。准确地做它所说的;比正则表达式更具可读性。
【解决方案3】:

您不需要为此使用正则表达式,因为您正在执行精确的字符串匹配(没有通配符、组等) - 您可以使用 str.startswith(..) 代替。这相当于您的代码:

for item in item_list:
    match = item + "."
    for file in search_list:
        if file.startswith(match)
            matches.append((item, file))

但是,Nick Craig-Wood 建议将所有匹配项编译成一个正则表达式可能更有效 - 如果速度是一个问题,我建议您对两者进行基准测试。

【讨论】:

    【解决方案4】:

    避免re,除非你真的需要它。对于简单的字符串匹配,你真的不需要它。

    Mark Byers 的回答重复了将matches 保留在item_list-order 中的原始行为。如果您不需要它,您可以更简单/快速地完成它:

    for file in search_list:
        item= os.path.splitext(file)[0]
        if item in item_list:
            matches.append((item, file))
    

    如果您也不需要保持 (item) 匹配(因为它在文件名中是多余的),那么您有一个单行:

    matches= [file for file in search_list if os.path.splitext(file)[0] in item_list]
    

    【讨论】:

    • 它们确实需要匹配,但感谢您提供了一个很好的单线示例!
    【解决方案5】:

    这是另一种可能比 Alex 的原始代码更快的方法:

    item_list = ['item1', 'item2']
    search_list = ['item1.exe', 'item2.pdf']
    matches = []
    for item in item_list:
        for filename in search_list:
            if filename.partition(".")[0] == item:
                matches.append((item,filename))
    

    【讨论】:

      【解决方案6】:
      >>> for file in search_list:
      ...  tomatch=file.split(".")[0]
      ...  if tomatch in item_list:
      ...     found=item_list.index(tomatch)
      ...     matches.append( ( file, item_list[found] ) )
      ...
      >>> print matches
      [('item1.exe', 'item1'), ('item2.pdf', 'item2')]
      >>>
      

      不需要正则表达式。

      【讨论】:

        【解决方案7】:

        我认为您应该为此使用.rsplit(".",1),正则表达式不是矫枉过正吗?

        >>> item_list = ['item1', 'item2','item3']
        >>> search_list = ['item1.exe', 'item2.pdf','item9999.txt']
        >>>
        >>> [(x.rsplit(".",1)[0],x) for x in search_list if x.rsplit(".",1)[0] in item_list]
        [('item1', 'item1.exe'), ('item2', 'item2.pdf')]
        

        或者用for循环

        matches=[]
        for x in search_list:
            y=x.rsplit(".",1)[0]
            if y in item_list:
                matches.append((y,x))
        

        【讨论】:

          猜你喜欢
          • 2022-01-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-03-27
          • 2010-11-03
          • 1970-01-01
          相关资源
          最近更新 更多