如何在Lua中高效地匹配表中的键?

在我的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"其中第二个字符无关紧要,或匹配数字..基本的东西)。 用这种附加的方法,我看不到恢复原始匹配模式的方法,以便我可以使用随之而来的值。

(最坏的情况是,我可以为了匹配每个可能的通配符变体而生成大量条目,并且不需要模式要求,但我真的不想这样做。)

哪个库是正确的工具,并且如何最好地使用该库来实现上述目标,而无需重新发明轮子?

点赞
用户6632736
用户6632736

一个回答你的问题提到了 Aho–Corasick 算法。

如果你的环境可以访问 os.executeio.popen,你可以调用 fgrep -o -f patterns filename,其中 patterns 是一个包含用换行符分隔的模式的文件名,filename 是你的输入文件名。-o 表示只输出匹配项,每行一个。你可以将 filename 替换为 -,这样 fgrep 就会从标准输入读取:echo "String to match" | fgrep -o -f patterns

fgrep 实现了 Aho–Corasick 算法。

但是要记住,Aho–Corasick 算法不识别元字符。

2020-09-22 01:10:29
用户17237579
用户17237579

就像 Alexander Mashin 的回答所说,Aho-Corasick 算法是一种高效的算法,可以解决您的问题。在 Lua 领域中,cloudflare/lua-aho-corasick 是一个使用 FFI 实现的 LuaJIT 实现。还有一个纯 Lua 实现 jgrahamc/aho-corasick-lua,它可能会更慢。

2021-10-25 03:16:00