如何在Python中优雅地迭代索引,以便对文本中的子串列表进行字符串匹配?

时间:2015-07-17 20:37:56

标签: python string-matching idioms sliding-window

Text是一个大字符串,patterns是一个短(固定)字符串列表。 我的代码是:

def BruteForcePatternMatching(text, patterns):
    indices = []
    for pattern in patterns:
        for index in range(len(text) - 1):
            slide = text[index : index + len(pattern) - 1]
            if pattern == slide:
                indices.append(index)
    return indices

我的问题是,如果有一个' pythonic'提取幻灯片的方法'来自文本,迭代大小。

2 个答案:

答案 0 :(得分:2)

您正试图在文字中找到与列表patterns匹配的内容。

如果patterns只是固定字符串,请使用string.find()(虽然请注意只会找到第一个匹配项 - 请参阅下文)。

s = 'cat dog cow dog' # Note 'dog' occurs multiply
s.find('dog')
4
s.find('cow')
8
s.find('cat')
0

更一般地说,如果模式具有正则表达式或具有重复的固定字符串,请使用re.findall/iter()。有关示例,请参阅此处的许多重复问题。

import re
pat = re.compile(r'(cat|dog|cow)')
pat.findall("The cat and cow sat on the dog's catalog of doggerel")
# ['cat', 'cow', 'dog', 'cat', 'dog']

如果您还需要匹配发生的索引,请使用re.finditer(),如@khachik所示。

注意我们将所有模式合并为一个正则表达式,然后使用一个re.findall()调用来搜索所有文本中每个模式的所有匹配项。 你当前的代码是非常低效的:它试图通过在文本上运行滑动窗口来测试字符串相等性,并且具有嵌套循环:一个覆盖文本中的所有N个索引,以及所有P模式;这将是订单O(N * P),这是不可扩展的。

答案 1 :(得分:1)

假设您的模式不包含任何特殊的正则表达式字符或者是正则表达式:

import re
indices = [(m.start(), m.end()) for m in re.finditer("|".join(patterns), text)]