我有一个相当复杂的regex搜索,最近我不得不将其扩展到"反向"模式.这很容易实现,但性能大约下降了10倍.
如果有任何关于如何改善这个问题的建议,我将不胜感激,但我对如何改进并不挑剔.例如,如果这比单个非常复杂的步骤快,那么可以使用两个或多个步骤.
Original pattern
import regex
expression = regex.compile(
fr"""
(?:{CUE}) # cue before targets. non capture (?:)
(?:{PADDING}) # text before the match.
(?:
(?:{ITEM_SEPARATION})? # none or once
(?P<targets>{targets_as_regex})
)+
""",
regex.VERBOSE,
)
需要知道:CUE
是一个很短的选项列表,类似于:
CUE = r"""word
|two\swords
|simple\soptions?
"""
这大约是5-15个选项,非常简单(对于相反的场景来说要简单一些).
PADDING
实际上是任何东西,但不超过150.(PADDING = r".{0,150}?"
).在相反的情况下,限制性更强一些,只有[,A-Za-z\d\s]
ITEM_SEPARATION
很简单:可选空格后跟逗号、有界"y"和更多可选空格:
ITEM_SEPARATION = r"""
\s* # optional spaces
(?:,|\by\b) # non-capture, either comma, or 'y' (with bounds)
\s* # optional spaces
"""
最后,问题可能出现在targets_as_regex
中,这是一个有界名称的大列表.这很容易有数百或数千个选项,尽管每个调用都会传递一个唯一的目标列表.
其目的是匹配以下内容:
这是一个文本,带有cue,然后多一点文本和match,other match y final match.在"."之后我们停止匹配.
而且它的性能足够好.但情况正好相反:
Reversed pattern
这样做的目的是:
这不是一场比赛,因为停了下来.这是matchanother matchyfinal match,因为现在我们找到了cue.等
我自然地回收了我的图案:
expression = regex.compile(
fr"""
(
(?P<targets>{targets_as_regex})
(?:{ITEM_SEPARATION})?
)+
(?:{SIMPLE_PADDING}) # text before the match
(?:{CUE_AFTER}) # cue after targets
""",
regex.VERBOSE,
)
它按预期工作,但当目标(很多)出现在线索(很少)之前时,性能非常差.
What I tried
我添加了一个基本判断,如果提示根本不在文本中,我们会忽略整个内容,但这并没有多大帮助.我测试过的另一个 idea 是搜索所有匹配的目标(不考虑提示和其他),然后将仅包含这些匹配的简短列表(targets_as_regex
)传递给慢速模式.这实际上有所帮助,但没有多大帮助(性能仍接近x10的下降).
还有其他的 idea 吗?