我正在寻找一种能够找到与特定字符串匹配的所有模式的高效算法。模式集可以非常大(超过100,000)和动态(随时添加或删除模式)。模式不一定是标准正则表达式,它们可以是正则表达式的子集或类似于shell模式的东西(即:file-*.txt
)。 首选正则表达式子集的解决方案(如下所述)。
仅供参考:我对基于RegExp列表的蛮力方法不感兴趣。
简单的正则表达式,我指的是一个支持?
,*
,+
,字符类[a-z]
以及可能的逻辑运算符|
的正则表达式。
澄清我的需求:我希望找到与URL匹配的所有模式:
http://site1.com/12345/topic/news/index.html
响应应该是基于下面设置的模式的这些模式。
http://*.site1.com/*/topic/*
http://*.site1.com/*
http://*
模式集:
http://*.site1.com/*/topic/*
http://*.site1.com/*/article/*
http://*.site1.com/*
http://*.site2.com/topic/*
http://*.site2.com/article/*
http://*.site2.com/*
http://*
答案 0 :(得分:2)
想到的一种方法是创建模式的树结构。
示例:http://*
将包含所有模式(如上所列)。 http://*.site1.com/*
将包含所有site1.com
个。这可以显着减少需要检查的模式数量。
此外,您可以确定哪些图案是互斥的,以进一步修剪您搜索的列表。
首先采取所有模式并从中创建树木。搜索所有根以确定需要分析哪些分支和节点。
通过确定哪些分支是互斥的来改进算法,因此一旦在给定分支上找到命中,就会知道不需要访问哪些分支/节点。
要开始你可能是懒惰的,你的第一个传递可能是对模式进行排序并做简单的下一个模式包含这个模式类型逻辑,以确定下一个是否包含“this”。 EX:if( "http://*.site1.com/*".startsWith("http://*") == true )
你可以更精确地确定一个模式是否确实包含另一个模式,但这会让你开始。
为了更好地确定问题:
“此模式是否包含该模式?”
我相信你需要能够解析正则表达式...这篇文章看起来是一个开始理解如何实现这一目标的好地方:Parsing regular expressions with recursive descent
答案 1 :(得分:1)
这是我成功使用的一种方法:
添加图案:
对于任何模式,字符串必须包含一组子字符串,以便有机会与之匹配。称这些元词。例如:
dog*fish -> [dog, fish]
[lfd]og -> [og]
dog? -> [dog]
在将模式添加到数据结构时,请将其分解为元词并将其存储在Aho-Corasick字符串匹配的数据结构中。维护内部数据结构,以将元词映射回模式词。
运行查询:
给出一个输入字符串,使用您构建的Aho-Corasick数据结构来获取该字符串中包含的所有元单词。然后,使用您创建的地图,测试与这些元词相对应的模式。
这很好用,因为尽管字符串匹配相当慢,但是您可以非常迅速地缩小实际必须匹配的模式的数量。我编写了此here的实现,可以在我的笔记本电脑上针对150,000多个模式集每秒执行约200,000个查询。请参见程序中的基准标记模式进行测试。
答案 2 :(得分:0)
如果这组URL没有快速变化,那么你真的应该使用一个编译其模式的正则表达式引擎。 Java提供了其中之一,但如果您想知道哪个模式匹配,则可能不会令人满意。
一种广泛使用的机制,用于执行和确定哪种匹配,是各种词法生成器,例如FLEX和类似工具。他们接受每个“lexeme”的正则表达式,并构建一个集成的FSA来识别任何非常有效的执行。
您可以在设置更改时调用Flex。如果这太慢,请获取Flex的开源版本并集成到您的引擎中;它在内部构建FSA,因此您可以直接使用它。 (某些工程可能是必要的)。但如果你真的有一个高性能匹配问题,一些做得好的工作不会打扰你。
如果URL集的变化速度快于FLEX可以生成FSA(奇数),那么您就遇到了一个真正的问题。在这种情况下,您可以通过从左到右扫描“正则表达式”并将您看到的字符/谓词集成到现有的识别树中来构建在线识别树。匹配则包括沿着辨别树走下去,进行各种测试;如果你到达一片叶子,你就有了匹配,否则没有。如果做得好,这可能与FLEX生成的自动化一样快,但可能很多,更大。