【发布时间】:2018-11-29 16:28:18
【问题描述】:
我正在寻找一种允许字符串到模式匹配的高效数据结构。这些模式遵循类似正则表达式的语法,但允许递归。它们包含可选项、选项和递归/通配符。一些模式示例如下:
how many * (are coming|came) to (the)? party
(drunk|sober)? people
annoying *
这些模式将匹配以下字符串:
how many drunk people are coming to the party
how many people came to party
how many annoying drunk people are coming to the party
那些会失败的:
how many are coming to the party <-- expected something else after 'many'
drunk sober people <-- has to be either 'drunk' or 'sober' but not both
语法与正则表达式基本相同。除了 * 期望在该位置有另一个匹配的模式。 () 是一个简单的组。 ()? 是一个可选组。 (choice1|choice2) 是一个选择组。
更多关于模式/输入的信息:
- 将有大约 10'000 个模式
- 大多数模式少于 200 个字符
- 模式应该支持 unicode 格式(尽管它们中的大多数可能只包含 ASCII 字符)
- 输入将是一个句子列表
- 每个句子都应该匹配一个模式(并且是嵌套模式)
- 句子通常少于 200 个字符
- 大多数句子包含少于 5 种不同的模式(一个例外 是带有算术表达式的句子,可能包含很多 更多模式)
- 大多数句子都是正确的,并且成功匹配了一个模式
- 验证一个句子是否有意义并不重要
要求:
- 数据结构应该是内存高效的(10MB 可能还可以, 100MB 不是)
- 数据结构应支持在运行时添加模式(删除不重要,添加不必太快)
- 构建数据结构不应花费太长时间(秒)
- 匹配应该相当快,超过 10'000 句/秒是目标
简单的解决方案 1 将所有模式存储在一个数组中,并尝试一个接一个地匹配,直到我们成功或到达列表的末尾。这会随着递归而变得非常缓慢。所以不是一个选择。
简单的解决方案 2 从所有可能的模式中构建一个前缀/patricia/... trie,并包含一些用于通配符的特殊节点。这更好,但每个可选/选择组都会创建额外的模式。这使得树“爆炸”非常快。尤其是因为它会创建许多靠近根部不同但靠近叶子的分支。
更复杂的解决方案 从模式中的单词创建一个 trie,并为它们分配一个唯一索引。使用 trie,我们可以将输入字符串转换为整数序列。但是我需要一些方法来将整数与模式匹配。不太确定该怎么做。
我觉得应该有一个很好的方法来解决这类问题。我想树表示是正确的选择,但我找不到任何适合该任务的算法/数据结构。有没有人处理过类似的问题并给我一些建议?
注意:这对我来说只是一个玩具项目。我不是在寻找一些生产质量工具,我也不在乎我需要多长时间来实施它。只是好奇是否存在一个好的解决方案。
【问题讨论】:
-
你检查过en.wikipedia.org/wiki/… 吗?
-
考虑构建一个有限状态机:en.wikipedia.org/wiki/Finite-state_machine.
-
@juvian 是的,我做到了,但这些算法用于精确的字符串匹配。
-
@JimMischel 状态机是一个选项,但我正在寻找更具体的东西。
-
我看到提到的递归,但没有看到任何例子。
标签: algorithm language-agnostic pattern-matching string-matching trie