有效地检查单词是否与集合中的模式匹配(Python)

时间:2013-02-10 23:02:41

标签: python glob

我有一套简单的通配模式和整个单词,如下所示:

s = set(['ALE', 'BREAD*', 'BREAKFAST*', 'BROTH' ...])

我还有很多单词。我想检查这个列表中的每个单词是否匹配a)集合中的globbing模式或b)集合中的单词。

如果没有通配模式,我会做类似的事情:

for word in words:
    if word in s:
        # do something

但是由于该集合也包含了globbing模式,如果我想将'BREADY'与'BREAD *'匹配,它将找不到匹配

我能想到这样做的唯一方法是使用嵌套的for循环将每个单词与集合中的每个模式进行比较。有没有办法可以检查每个单词在集合中是否匹配而不将其与集合中的每个元素进行比较?

3 个答案:

答案 0 :(得分:1)

您应该将要匹配的完整字符串与要匹配的前缀分开存储。对于你的前缀,进一步将它们分成等长前缀的集合(即一组长度为1的前缀,一组长度为2的前缀等)。

fullstrings = set(["BREAKFAST", "LUNCH", "DINNER", ...])
prefixes_by_length = {} # dict of length -> prefix string
...
prefixes_by_length[4] = set(["CORN", "DESK", ...])
prefixes_by_length[5] = set(["BREAD", "TABLE", ...])

完整字符串匹配很简单 - 只需检查word in fullstrings

对于前缀,您将分别检查每个长度,从长度1开始到您想要匹配的最大前缀长度。对于每个n长度,请检查word[:n] in prefixes_by_length[n]

如果你有很多这些前缀,那么每次循环所有前缀都会非常有效。

for word in words:
    if word in fullstrings:
        "Match! do something"
    for n in prefixes_by_length:
        if word[:n] in prefixes_by_length[n]:
            "Match! do something"

答案 1 :(得分:1)

授予OP不想循环。

import re
import fnmatch
s = set(['ALE', 'BREAD*', 'BREAKFAST*', 'BROTH'])
patterns = [re.compile(fnmatch.translate(p)) for p in s]

for word in "BEING PALE I LIKE ALE WITH BREADDY ABROTH FOR BREAKFASTY TREATS AND BROTH".split():
    for pattern in patterns:
        if pattern.match(word):
            print "HIT", word

给出:

HIT ALE
HIT BREADDY
HIT BREAKFASTY
HIT BROTH

答案 2 :(得分:0)

假设我们有一个词汇表words和一个搜索列表searches。对于您提供的简单示例,以下内容就足够了。

for word in words:
    for search in searches:
        if search[-1] == "*":
            search = search[:-1]
            if word.lower().startswith(search.lower()):
                yield word
        else:
            if word.lower() == search.lower():
                yield word