簡體   English   中英

檢查字符串是否包含列表中的至少一個字符串

[英]Check if a string contains at least one of the strings in a list

我正在嘗試使用python進行匹配。

我有一個字符串列表(len~3000)和一個文件,我想檢查文件中的每一行是否至少有一個列表中的字符串。

最直接的方法是逐個檢查,但需要時間(不過很長時間)。

有沒有辦法可以更快地搜索?

例如:

list = ["aq", "bs", "ce"]

if the line is "aqwerqwerqwer"  -> true (since has "aq" in it)
if the line is "qweqweqwe" -> false (has none of "aq", "bs" or "ce")

您可以使用anygenerator表達式

# Please do not name a list "list" -- it overrides the built-in
lst = ["a", "b", "c"]
if any(s in line for s in lst):
    # Do stuff

上面的代碼將測試是否可以line找到lst任何項目。 如果是這樣, # Do stuff將會運行。

請參閱下面的演示:

>>> lst = ["aq", "bs", "ce"]
>>> if any(s in "aqwerqwerqwer" for s in lst):
...     print(True)
...
True
>>> if any(s in "qweqweqwe" for s in lst):
...     print(True)
...
>>>

這實際上是使用帶有自動創建的正則表達式的正則表達式引擎的一個很好的用例。

嘗試:

def re_match(strings_to_match, my_file):
    # building regular expression to match
    expression = re.compile(
        '(' + 
        '|'.join(re.escape(item) for item in strings_to_match) +
        ')')

    # perform matching
    for line in my_file:
        if not expression.search(line):
            return False
    return True

正則表達式將比每個字符串的簡單線性掃描更快,以匹配每一行。 這有兩個原因:正則表達式是用C實現的,正則表達式被編譯成一個狀態機,它只檢查一次輸入字符,而不是天真解決方案中的幾次。

請參閱IPython筆記本中的比較: http//nbviewer.ipython.org/gist/liori/10170227 測試數據由3000個字符串組成,以匹配100萬行的列表。 天真的方法在我的機器上花了1分46秒,而這個解決方案只有9.97秒。

你可以使用itertools.groupby:

from itertools import groupby
pats = ['pat', 'pat2', …]
matches = groupby(lines, keyfunc=lambda line:any(pat in line for pat in pats))

如果您的模式都是單個字符串,則可以使用集合進一步優化:

pats = set('abcd')
matches = groupby(lines, keyfunc=pats.intersection)

這將導致類似的迭代

[(matched patterns, lines matched),
 (empty list, lines not matched),
 (matched patterns, lines matched),
 …]

(除了它將是一個生成器,而不是一個列表。)這是它的主要邏輯。 以下是將預處理的生成器迭代到產品輸出的一種方法。

for linegrp in matches:
  for line in matched_pats, linegrp:
    if matched_pats:
      print('"{}" matched because of "{}"'.format(line, matched_pats))
    else:
      print('"{}" did not match')

更多參與但速度更快:將您的字符串列表預處理為前綴trie。

然后,對於每個文件行,從每個字符位置開始,查看您可以走多遠。

如果您保留所有活動嘗試的隊列,則只需在掃描線時查看每個字符位置一次。 您還可以在每個trie節點處包含一個“最小終端深度”計數器,以便在接近字符串末尾時提前截斷比較。


更簡單的一步是將您的大字符串列表減少為字符串列表的字典,由您要查找的每個字符串的前三個字符索引。

from itertools import count, tee, izip

def triwise(iterable):
    # base on pairwise, from the itertools documentation
    "s -> (s0,s1,s2), (s1,s2,s3), (s2,s3,s4), ..."
    a, b, c = tee(iterable, 3)
    next(b, None)
    next(c, None)
    next(c, None)
    return izip(a, b, c)

class Searcher:
    def __init__(self):
        self.index = {}

    def add_seek_strings(self, strings):
        for s in strings:
            pre = s[:3]
            if pre in self.index:
                self.index[pre].append(s)
            else:
                self.index[pre] = [s]

    def find_matches(self, target):
        offset = -1
        for a,b,c in triwise(target):
            offset += 1
            pre = a+b+c
            if pre in self.index:
                from_here = target[offset:]
                for seek in self.index[pre]:
                    if from_here.startswith(seek):
                        yield seek

    def is_match(self, target):
        for match in self.find_matches(target):
            return True
        return False

def main():
    srch = Searcher()
    srch.add_seek_strings(["the", "words", "you", "want"])

    with open("myfile.txt") as inf:
        matched_lines = [line for line in inf if srch.is_match(line)]

if __name__=="__main__":
    main()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM