#regex #filter #multiple #pattern-matching #state-machine #filtered-re2 #prefilter

regex-filtered

高效地检查输入与大量模式之间的匹配

3个不稳定版本

0.2.0 2024年6月22日
0.1.1 2024年6月17日
0.1.0 2024年6月17日

324算法

Download history 348/week @ 2024-06-16 42/week @ 2024-06-23

108 每月下载量
用于 ua-parser

BSD-3-Clause

715KB
1K SLoC

regex-filtered: rust-regex的FilteredRE2

此crate在FilteredRE2之上实现了regex的逻辑。

其目的是允许从一组大量模式中选择一个或多个与输入匹配的正则表达式,而不必逐个检查每个正则表达式,通过预过滤候选正则表达式,只匹配输入。

如果正则表达式非平凡(例如,非字面量),则应优先使用此功能,因为regex::RegexSet会构建一个单一的状态机,它会迅速变得庞大且缓慢。

线性匹配没有这个问题,并且可以很好地处理复杂正则表达式,但是随着正则表达式数量的增加,它无法扩展,匹配失败的成本很快就会非常高(因为每次都需要遍历整个集合)。

用法

let matcher = regex_filtered::Builder::new()
    .push("foo")?
    .push("bar")?
    .push("baz")?
    .push("quux")?
    .build()?;

assert!(matcher.is_match("bar"));
assert_eq!(matcher.matching("baz").count(), 1);
assert_eq!(matcher.matching("foo quux").count(), 2);
# Ok::<(), Box<dyn std::error::Error>>(())

Regexes::is_match返回集合中是否存在任何模式与需要查找的文本匹配。这基本上等同于 matcher.matching(...).next().is_some()

Regexes::matching 返回匹配的 regex::Regex 和相应索引的迭代器。索引可以用于查找辅助数据(例如替换内容),而 regex::Regex 可以用于 regex::Regex::findregex::Regex::captures 从文本中提取数据。

注意

regex-filtered 仅返回匹配的正则表达式(及其索引),因为捕获通常比检查匹配要花费更多,这可能会对预先过滤剪裁完美的场景产生轻微的不利影响,但在预先过滤不适用且需要后过滤的情况下,这可以带来很大的收益。

概念

从大量正则表达式中提取区分性的文本标记,将标记与输入匹配,反向查找匹配的标记对应哪些正则表达式,然后在输入上仅运行相应的正则表达式。

此提取是通过收集文本项,将它们转换为内容集,然后符号执行连接和交替(|)来完成的,以找出哪些文本项需要存在于文本中以便该正则表达式匹配。然后从文本项到正则表达式构建一个反向索引。

在匹配时,运行预先过滤程序检查文本中存在哪些文本,然后找出相应的正则表达式,之后将正则表达式本身与文本匹配,以仅返回实际匹配的正则表达式。

差异

虽然 FilteredRE2 要求用户执行预先过滤,但 regex-filtered 在内部处理此操作:aho-corasick 几乎是这项任务的理想选择,并且已经是 regex 的依赖项,而 regex-filtered 是基于 regex 开发的。

待办事项

  • 添加统计功能以报告各种构建大小信息,例如:

    • 标记数量
    • 正则表达式数量
    • 未过滤的正则表达式数量,这将有助于了解是否需要进行预先过滤或直接顺序应用会更好。
    • 已检查的正则表达式与成功比例(与懒惰迭代器如何一起工作?)
    • 总数/预先过滤(-未过滤)以评估原子大小影响
    • 也许还有修剪操作的映射器统计信息等

依赖关系

~3.5–5MB
~85K SLoC