在我的Lua 5.1环境中可用显然是默认的Lua模式匹配,但也是PCRE和LPEG的合理最新版本。老实说,我不在乎使用其中哪一个;只要我的问题以有效的方式得到解决,我就很高兴。(我个人对LPEG的了解几乎不存在,但我听说它有一些非常好的品质。
我有一个表,其中某些字符串模式作为键,一旦键匹配,就会使用随附的值......这意味着它们在这件事上并不重要。
假设您有:
tbl = { ["aaa"] = 12, ["aab"] = 452, ["aba"] = -2 }
现在我的目标是找出这些匹配项中的哪一个首先在特定字符串中,例如"accaccaacaadacaabacdaaba"
.
实际上,键的数量更多,匹配字符串也更长。这意味着简单地逐个匹配所有键并比较匹配开始的列是一个非常低效的解决方案,对我来说是不可行的。
匹配字符串的某些部分也可能有相当大的重叠。从理论上,我知道每个键模式一个状态机在这方面是理想的;只需浏览每种模式的动作,当您在其中一种模式上完全匹配时,您就完成了。
但是,当我的环境中有这么多模式匹配库时,我会疯狂地自己编写这样的东西。我知道唯一具有技术能力的是 PCRE;只需附加像"aaa|aab|aba"
这样的键,你就会得到第一个可行的匹配。
但也有问题。首先,我不确定在编译这样的匹配时它有多聪明。(我认为它首先尝试"aaa",失败后完全展开,然后完全尝试 aab,但我还没有测试过)与像"a(a[ab]|ba)"
这样更快地解决相似之处的匹配相比,这不会太有效。
此外,我希望有能力增加一些灵活性("a.ad",其中第二个字符无关紧要,或者匹配数字......类似的基本内容)。在这种加法方法中使用这样的模式,我看不到一种方法可以重新获得匹配的原始模式,以便我可以使用随之而来的值。
(最坏的情况是,我可以在表中生成大量条目以匹配每个可能的通配符变体并取消模式要求,但老实说我不想这样做。
哪个库是适合这项工作的工具,为了启动,如何最好地使用所述库来实现上述目标,而无需重新发明轮子?
对你的问题的评论提到了Aho-Corasick 算法。
如果您的环境可以访问os.execute
或io.popen
,则可以调用fgrep -o -f patterns filename
,其中patterns
是包含用换行符分隔的模式的文件的名称,文件名是输入的名称。-o
意味着将仅输出匹配项,每行一个。您可以将filename
替换为-
,以便fgrep
从标准输入读取:echo "String to match" | fgrep -o -f patterns
。
fgrep
实现了Aho-Corasick 算法。
但是,请记住,Aho-Corasick 算法无法识别元字符。
正如Alexander Mashin的回答所说,Aho-Corasick 算法是一种有效的算法,可以解决你的问题。在卢阿土地上,云焰/lua-aho-corasick 是使用 FFI 的 LuaJIT 实现。还有一个纯粹的lua implemetation jgrahamc/aho-corasick-lua,它可能更慢。