我正在尝试执行正则表达式以匹配文档中的多个n-gram。 我首先得到一个n-gram列表,我将它们编译成正则表达式,如下所示:
sNgrams = '|'.join(('\s+'.join(re.escape(gram) for gram in nGram.split())) for nGram in aNgrams)
(将n-gram拆分为任何空格字符上的标记,重新设置这些标记并将它们与'\ s +' - es连接起来(所以我可以在新行,双空格,制表符和诸如此类的地方匹配ngrams),以及然后用正则表达式的'|'加入n-gram
我的正则表达式如下:
reNgram = re.compile('(\A|\W+)(' + sNgrams + ')(?=\W+|\Z)',flags=re.UNICODE|re.IGNORECASE)
现在,这适用于大多数情况,但是,当n-gram与另一个重叠时,只找到一个匹配:
doc = 'aap noot mies'
aNgrams = ['aap','noot','aap noot']
sNgrams = 'aap|noot|aap\\s+noot'
re.findall(reNgram,doc)
[('', 'aap'), (' ', 'noot')]
aNgrams = ['mies','aap noot']
re.findall(reNgram,doc)
[('', 'aap noot'), (' ', 'mies')]
有什么方法可以解决这个问题吗?返回匹配的所有(子)字符串 在文件中?
此外,速度/效率非常重要 (我正在解雇成千上万的这些正则表达式),有什么我的 可以做优化吗?我已经读过预编译正则表达式没有 做得多,因为无论如何都会缓存“即时”编译的正则表达式,是否有任何(其他)明显的步骤可以加速这些表达式?
答案 0 :(得分:3)
我认为你不能用一个正则表达式做到这一点。
你可以靠近一点
现在,可以找到noot
之后的实际重叠匹配(app noot
):
>>> sNgrams = '|'.join(('\s+'.join(re.escape(gram)
... for gram in nGram.split()))
... for nGram in reversed(sorted(aNgrams, key=len)))
>>> sNgrams
'aap\\s+noot|noot|aap'
>>> reNgrams = re.compile(r"(?<!\w)(?=(" + sNgrams + r")(?!\w))",
... flags=re.UNICODE|re.IGNORECASE)
>>> reNgrams.findall(doc)
['aap noot', 'noot']
但它仍然找不到aap
和aap noot
。正则表达式只能在字符串中的每个位置报告一个匹配项,因此它必须与两个中的一个匹配。
要解决此问题,您必须将n-gram列表拆分为列表,其中没有字符串以相同的单词开头,并按顺序应用这些正则表达式。我怀疑这不会很高效,但我没有看到任何其他方式(除了检查自己的正则表达式中的每个单词,并且这也不会非常快)。