#regex #string #string-search #regular #match #automata #expression

无 std regex

Rust 中正则表达式的实现。这个实现使用有限自动机,并保证在所有输入上都能进行线性时间匹配。

155 个版本 (67 个稳定版)

1.10.6 2024 年 8 月 2 日
1.10.5 2024 年 6 月 9 日
1.10.4 2024 年 3 月 23 日
1.10.2 2023 年 10 月 16 日
0.1.4 2014 年 12 月 23 日

文本处理 中排名 第 1

Download history 2643033/week @ 2024-05-03 2686279/week @ 2024-05-10 2727437/week @ 2024-05-17 2604305/week @ 2024-05-24 2803534/week @ 2024-05-31 3016966/week @ 2024-06-07 2941245/week @ 2024-06-14 2959405/week @ 2024-06-21 2633233/week @ 2024-06-28 2824951/week @ 2024-07-05 2906983/week @ 2024-07-12 2969548/week @ 2024-07-19 2945643/week @ 2024-07-26 3195074/week @ 2024-08-02 3453922/week @ 2024-08-09 2799938/week @ 2024-08-16

每月下载量 12,931,790
42,598 个 Crates (9,760 直接) 中使用

MIT/Apache 许可

3.5MB
54K SLoC

regex

这个 Crate 提供了用于在字符串中搜索正则表达式匹配项的例程(即 "regex")。此 Crate 支持的 regex 语法与其他 regex 引擎类似,但缺乏一些难以高效实现的特性。这包括但不限于前瞻和后引用。作为交换,此 Crate 中的所有 regex 搜索都有最坏情况的 O(m * n) 时间复杂度,其中 m 与正则表达式的大小成比例,n 与被搜索字符串的大小成比例。

Build status Crates.io

文档

模块文档及示例。模块文档还包括对支持的语法的全面描述。

有关各种匹配函数和迭代器的示例文档可以在 Regex 类型 上找到。

使用

要将此 Crate 添加到您的仓库,请将 regex 添加到您的 Cargo.toml,或运行 cargo add regex

以下是一个简单的示例,匹配 YYYY-MM-DD 格式的日期,并打印年、月和日

use regex::Regex;

fn main() {
    let re = Regex::new(r"(?x)
(?P<year>\d{4})  # the year
-
(?P<month>\d{2}) # the month
-
(?P<day>\d{2})   # the day
").unwrap();

    let caps = re.captures("2010-03-14").unwrap();
    assert_eq!("2010", &caps["year"]);
    assert_eq!("03", &caps["month"]);
    assert_eq!("14", &caps["day"]);
}

如果您有很多以文本形式表示的日期需要遍历,则可以轻松地使用迭代器修改上述示例

use regex::Regex;

fn main() {
    let re = Regex::new(r"(\d{4})-(\d{2})-(\d{2})").unwrap();
    let hay = "On 2010-03-14, foo happened. On 2014-10-14, bar happened.";

    let mut dates = vec![];
    for (_, [year, month, day]) in re.captures_iter(hay).map(|c| c.extract()) {
        dates.push((year, month, day));
    }
    assert_eq!(dates, vec![
      ("2010", "03", "14"),
      ("2014", "10", "14"),
    ]);
}

使用说明:避免在循环中编译相同的 regex

在循环中编译相同的正则表达式是一种反模式,因为编译通常很昂贵。编译时间从几微秒到几毫秒不等,这取决于正则表达式的大小。编译本身就很昂贵,而且这也阻碍了匹配引擎内部重用分配的优化。

在Rust中,如果正则表达式在辅助函数内部使用,有时传递它们可能会很麻烦。相反,我们建议使用once_cell crate来确保正则表达式只编译一次。例如

use {
    once_cell::sync::Lazy,
    regex::Regex,
};

fn some_helper_function(haystack: &str) -> bool {
    static RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"...").unwrap());
    RE.is_match(haystack)
}

fn main() {
    assert!(some_helper_function("abc"));
    assert!(!some_helper_function("ac"));
}

具体来说,在这个例子中,正则表达式将在首次使用时进行编译。在随后的使用中,它将重用之前的编译。

使用方法:在&[u8]上匹配正则表达式

此crate的主要API(regex::Regex)要求调用者传递一个用于搜索的&str。在Rust中,&str必须有效UTF-8,这意味着主API不能用于搜索任意字节。

要匹配任意字节,请使用regex::bytes::Regex API。该API与主API相同,只是它使用一个&[u8]来搜索,而不是一个&str。这些&[u8] API还允许在正则表达式中禁用Unicode模式,即使模式会匹配无效UTF-8。例如,在regex::Regex中不允许使用(?-u:.),但在regex::bytes::Regex中允许,因为(?-u:.)匹配任何字节(除了\n)。相反,.将匹配除\n之外的任何Unicode标量值的UTF-8编码。

此示例显示了如何在一个字节的切片中找到所有空终止字符串

use regex::bytes::Regex;

let re = Regex::new(r"(?-u)(?<cstr>[^\x00]+)\x00").unwrap();
let text = b"foo\xFFbar\x00baz\x00";

// Extract all of the strings without the null terminator from each match.
// The unwrap is OK here since a match requires the `cstr` capture to match.
let cstrs: Vec<&[u8]> =
    re.captures_iter(text)
      .map(|c| c.name("cstr").unwrap().as_bytes())
      .collect();
assert_eq!(vec![&b"foo\xFFbar"[..], &b"baz"[..]], cstrs);

注意这里,[^\x00]+将匹配任何字节,除了NUL,包括像\xFF这样的字节,这些字节不是有效的UTF-8。当使用主API时,[^\x00]+将匹配除NUL之外的任何有效的UTF-8序列。

使用方法:同时匹配多个正则表达式

此示例演示了如何使用RegexSet在搜索文本的单次扫描中匹配多个(可能重叠的)正则表达式

use regex::RegexSet;

let set = RegexSet::new(&[
    r"\w+",
    r"\d+",
    r"\pL+",
    r"foo",
    r"bar",
    r"barfoo",
    r"foobar",
]).unwrap();

// Iterate over and collect all of the matches.
let matches: Vec<_> = set.matches("foobar").into_iter().collect();
assert_eq!(matches, vec![0, 2, 3, 4, 6]);

// You can also test whether a particular regex matched:
let matches = set.matches("foobar");
assert!(!matches.matched(5));
assert!(matches.matched(6));

使用方法:将正则表达式内部作为库

regex-automata 目录》包含一个crate,它暴露了《regex》crate使用的所有内部匹配引擎。其想法是《regex》crate为99%的使用场景提供了一个简单的API,但《regex-automata》则暴露了大量的可定制行为。

regex-automata》的文档。

用法:正则表达式解析器

此仓库包含一个crate,它提供了一个经过良好测试的正则表达式解析器、抽象语法和高级中间表示形式,便于分析。它不提供编译或执行的功能。如果你正在实现自己的正则表达式引擎或需要对正则表达式的语法进行分析,这可能很有用。否则,不建议一般使用。

regex-syntax》的文档。

crate功能

此crate包含几个功能,允许调整二进制大小、编译时间和运行时性能之间的权衡。此crate的用户可以选择性地禁用Unicode表,或从此crate执行的各种优化中选择禁用。

当禁用所有这些功能时,运行时匹配性能可能会大大降低,但如果你在短字符串上进行匹配,或者高性能不是必需的,那么这种配置完全适用。要禁用所有这些功能,请使用以下Cargo.toml依赖配置:

[dependencies.regex]
version = "1.3"
default-features = false
# Unless you have a specific reason not to, it's good sense to enable standard
# library support. It enables several optimizations and avoids spin locks. It
# also shouldn't meaningfully impact compile times or binary size.
features = ["std"]

这将把regex的依赖树缩减到两个crate:`regex-syntax`和`regex-automata`。

可以禁用的完整功能集位于文档的“crate功能”部分

性能

此crate的一个目标是使正则表达式引擎“快速”。这个目标有些模糊,通常有两种解释方式。首先,这意味着所有搜索都将在最坏情况下以O(m * n)的时间进行,其中mlen(regex)成比例,nlen(haystack)成比例。其次,这意味着即使在时间复杂度约束之外,正则表达式搜索在实际情况中也是“快速”的。

虽然第一种解释非常明确,但第二种解释仍然模糊。虽然模糊,但它指导了此crate的架构和它所做出的权衡。例如,以下是一些由于追求“快速”目标而产生的通用架构陈述:

  • 当需要在更快的正则表达式搜索和更快的Rust编译时间之间做出选择时,此crate通常会选择更快的正则表达式搜索。
  • 当需要在更快的正则表达式搜索和更快的正则表达式编译时间之间做出选择时,此crate通常会选择更快的正则表达式搜索。也就是说,如果这意味着搜索会更快,那么《Regex::new`会稍微慢一些是完全可以接受的。(这是一个需要小心权衡的问题,因为《Regex::new`的速度需要保持合理。这就是为什么应该避免反复重新编译相同的正则表达式的原因。)
  • 在需要选择更快的正则表达式搜索和更简单的API设计时,这个crate通常会选择更快的正则表达式搜索。例如,如果一个人不关心性能,我们可以去掉Regex::is_matchRegex::find这两个API,而仅仅依赖于Regex::captures

或许还有更多的方式是“快速”影响事物的。

虽然这个仓库曾经提供自己的基准测试套件,但它现在已经移至rebar。基准测试非常全面,比rebar的README中显示的要多得多(它仅限于一个“精选”集合,旨在比较正则表达式引擎的性能)。要运行这个crate的所有基准测试,首先开始通过克隆和安装rebar

$ git clone https://github.com/BurntSushi/rebar
$ cd rebar
$ cargo install --path ./

然后构建这个crate的基准测试工具

$ rebar build -e '^rust/regex$'

以测试的方式运行这个crate的所有基准测试(每个基准测试只执行一次以确保其工作正常)

$ rebar measure -e '^rust/regex$' -t

记录所有基准测试的测量值并将它们保存到CSV文件中

$ rebar measure -e '^rust/regex$' | tee results.csv

探索基准测试的时间

$ rebar cmp results.csv

查看rebar的文档以获取更多关于其工作方式和如何与其他正则表达式引擎比较结果的信息。

黑客

regex crate主要是对meta::Regex的简单包装,后者来自regex-automata crate。因此,如果你想研究这个crate的内部结构,你可能会想查看regex-syntax(用于解析)或regex-automata(用于有限自动机的构建和搜索例程)。

我的关于正则表达式内部的博客进行了更深入的探讨。

最低Rust版本策略

这个crate最低支持的rustc版本是1.65.0

政策是,用于使用这个crate所需的最低Rust版本可以在小版本更新中提高。例如,如果regex 1.0需要Rust 1.20.0,那么regex 1.0.z的所有值也将需要Rust 1.20.0或更高版本。然而,regex 1.y对于y > 0可能需要更高的最低Rust版本。

许可证

本项目可使用以下任一许可证:

任选其一。

regex-syntax/src/unicode_tables/中的数据受Unicode许可证协议(LICENSE-UNICODE)许可。

依赖项