我正在寻找解决这个问题的最佳算法:拥有一个小句子的列表(或一个字典,一组),在更大的文本中找到所有出现的句子。列表中的句子(或词典或集合)约为600k,但平均形成3个单词。该文本平均长度为25个字。我刚刚格式化了文本(删除标点符号,全部小写并继续这样)。
这是我尝试过的(Python):
to_find_sentences = [
'bla bla',
'have a tea',
'hy i m luca',
'i love android',
'i love ios',
.....
]
text = 'i love android and i think i will have a tea with john'
def find_sentence(to_find_sentences, text):
text = text.split()
res = []
w = len(text)
for i in range(w):
for j in range(i+1,w+1):
tmp = ' '.join(descr[i:j])
if tmp in to_find_sentences:
res.add(tmp)
return res
print find_sentence(to_find_sentence, text)
输出:
['i love android', 'have a tea']
在我的情况下,我使用了一套来加速in
操作
答案 0 :(得分:5)
快速解决方案是从句子中构建Trie
并将此trie转换为正则表达式。对于您的示例,模式将如下所示:
(?:bla\ bla|h(?:ave\ a\ tea|y\ i\ m\ luca)|i\ love\ (?:android|ios))
最好将'\b'
添加为字边界,以避免匹配"have a team"
。
你需要一个小Trie script。它还不是官方软件包,但您可以在当前目录中将其here下载为trie.py
。
然后,您可以使用此代码生成trie / regex:
import re
from trie import Trie
to_find_sentences = [
'bla bla',
'have a tea',
'hy i m luca',
'i love android',
'i love ios',
]
trie = Trie()
for sentence in to_find_sentences:
trie.add(sentence)
print(trie.pattern())
# (?:bla\ bla|h(?:ave\ a\ tea|y\ i\ m\ luca)|i\ love\ (?:android|ios))
pattern = re.compile(r"\b" + trie.pattern() + r"\b", re.IGNORECASE)
text = 'i love android and i think i will have a tea with john'
print(re.findall(pattern, text))
# ['i love android', 'have a tea']
你花了一些时间来创建Trie和正则表达式,但处理速度应该非常快。
如果您想了解更多信息,请参阅related answer (Speed up millions of regex replacements in Python 3)。
请注意,它找不到重叠的句子:
to_find_sentences = [
'i love android',
'android Marshmallow'
]
# ...
print(re.findall(pattern, "I love android Marshmallow"))
# ['I love android']
您必须使用正向前瞻修改正则表达式才能找到重叠的句子。