rust-lang/regex
GitHub: rust-lang/regex
Rust官方正则表达式库,采用有限自动机实现,保证线性时间匹配,避免ReDoS风险。
Stars: 3935 | Forks: 496
# regex
该 crate 提供了用于搜索字符串以查找[正则表达式] (aka "regex") 匹配的例程。该 crate 支持的正则表达式语法与其他正则表达式引擎类似,但缺乏一些尚不知道如何高效实现的功能。这包括但不限于 look-around 和 backreferences。作为交换,该 crate 中的所有正则表达式搜索都具有最坏情况 `O(m * n)` 时间复杂度,其中 `m` 与正则表达式的大小成正比,`n` 与被搜索字符串的大小成正比。
[](https://github.com/rust-lang/regex/actions)
[](https://crates.io/crates/regex)
### 文档
[包含示例的模块文档](https://docs.rs/regex)。
该模块文档还包含对所支持语法的全面描述。
关于各种匹配函数和迭代器的文档及示例可以在
[`Regex` type](https://docs.rs/regex/*/regex/struct.Regex.html) 中找到。
### 用法
要将此 crate 引入您的仓库,可以将 `regex` 添加到您的 `Cargo.toml` 中,或者运行 `cargo add regex`。
这是一个匹配 YYYY-MM-DD 格式日期并打印年、月和日的简单示例:
```
use regex::Regex;
fn main() {
let re = Regex::new(r"(?x)
(?P\d{4}) # the year
-
(?P\d{2}) # the month
-
(?P\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"),
]);
}
```
### 用法:避免在循环中编译同一个正则表达式
在循环中编译相同的正则表达式是一种反模式,因为编译通常开销较大。(根据正则表达式的大小,这需要几微秒到几 **毫秒** 不等。)不仅编译本身开销大,而且这还会阻碍在匹配引擎内部重用分配的优化。
在 Rust 中,如果在辅助函数内部使用正则表达式,传递它们有时会很麻烦。相反,如果您不能使用标准库,我们建议使用 [`std::sync::LazyLock`] 或 [`once_cell`] crate。
此示例展示了如何使用 `std::sync::LazyLock`:
```
use std::sync::LazyLock;
use regex::Regex;
fn some_helper_function(haystack: &str) -> bool {
static RE: LazyLock = LazyLock::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。例如,`(?-u:.)` 在 `regex::Regex` 中是不允许的,但在 `regex::bytes::Regex` 中是允许的,因为 `(?-u:.)` 匹配除 `\n` 之外的任何字节。相反,`.` 将匹配除 `\n` 之外的任何 Unicode 标量值的 UTF-8 编码。
此示例展示了如何在字节切片中查找所有以空字符结尾的字符串:
```
use regex::bytes::Regex;
let re = Regex::new(r"(?-u)(?[^\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` directory](./regex-automata/) 包含一个 crate,它公开了 `regex` crate 使用的所有内部匹配引擎。其理念是 `regex` crate 为 99% 的用例公开了一个简单的 API,但 `regex-automata` 公开了大量可自定义的行为。
[`regex-automata` 的文档](https://docs.rs/regex-automata)。
### 用法:正则表达式解析器
此仓库包含一个 crate,它提供了一个经过充分测试的正则表达式解析器、抽象语法和高级中间表示,以便于分析。它不提供编译或执行功能。如果您正在实现自己的正则表达式引擎,或者需要分析正则表达式的语法,这可能会很有用。否则,不建议一般使用。
[`regex-syntax` 的文档](https://docs.rs/regex-syntax)。
### Crate 功能
此 crate 附带多个功能,允许在二进制大小、编译时间和运行时性能之间进行调整。此 crate 的用户可以选择性地禁用 Unicode 表,或从该 crate 执行的各种优化中进行选择以禁用。
当所有这些功能都被禁用时,运行时匹配性能可能会差很多,但如果您匹配的是短字符串,或者不需要高性能,那么这样的配置是完全可用的。要禁用所有此类功能,请使用以下 `Cargo.toml` 依赖配置:
```
[dependencies.regex]
version = "1.3"
default-features = false
# 除非有特定理由,否则启用标准库支持是明智之举。它可启用多项优化并避免自旋锁。此外,这也不应对编译时间或二进制大小产生显著影响。
# 库支持。它启用了若干优化并避免了自旋锁。
# 此外,它不应显著影响编译时间或二进制大小。
features = ["std"]
```
这将把 `regex` 的依赖树减少到两个 crate:`regex-syntax` 和 `regex-automata`。
可以禁用的完整功能集位于[文档的 "Crate features" 部分](https://docs.rs/regex/1.*/#crate-features)。
### 性能
此 crate 的目标之一是使正则表达式引擎“快”。虽然这是一个有点模糊的目标,但它通常被解释为两种方式之一。首先,这意味着所有搜索的最坏情况时间复杂度为 `O(m * n)`,其中 `m` 与 `len(regex)` 成正比,`n` 与 `len(haystack)` 成正比。其次,这意味着除了时间复杂度限制之外,正则表达式搜索在实践中是“快”的。
虽然第一种解释相当明确,但第二种解释仍然模糊。虽然模糊,但它指导了此 crate 的架构及其所做的权衡。例如,以下是作为“快”目标的结果而遵循的一些通用架构声明:
* 当在更快的正则表达式搜索和更快的 _Rust 编译时间_ 之间做出选择时,此 crate 通常会选择更快的正则表达式搜索。
* 当在更快的正则表达式搜索和更快的 _正则表达式编译时间_ 之间做出选择时,此 crate 通常会选择更快的正则表达式搜索。也就是说,如果 `Regex::new` 变慢一点但搜索变得更快,通常是可以接受的。(这是一个相当微妙的平衡,因为 `Regex::new` 的速度需要保持在一定程度上合理。但这就是为什么应该避免一遍又一遍地重新编译同一个正则表达式。)
* 当在更快的正则表达式搜索和更简单的 API 设计之间做出选择时,此 crate 通常会选择更快的正则表达式搜索。例如,如果不关心性能,我们可能会去掉 `Regex::is_match` 和 `Regex::find` API,而只依赖 `Regex::captures`。
可能还有更多“快”影响事物的方式。
虽然此仓库过去提供自己的基准测试套件,但后来已移至 [rebar](https://github.com/BurntSushi/rebar)。基准测试非常广泛,比 rebar 自述文件中显示的要多得多(后者仅限于旨在比较正则表达式引擎之间性能的“精选”集合)。要运行此 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` 文档。
### Hacking
`regex` crate 在很大程度上只是 [`regex-automata` crate](https://docs.rs/regex-automata/latest/regex_automata/) 中 [`meta::Regex`](https://docs.rs/regex-automata/latest/regex_automata/meta/struct.Regex.html) 的一个相当薄的封装。因此,如果您打算研究此 crate 的内部结构,您可能需要查看 `regex-syntax`(用于解析)或 `regex-automata`(用于构建有限自动机和搜索例程)。
我的[关于正则表达式内部机制的博客](https://burntsushi.net/regex-internals/)进行了更深入的探讨。
### 最低 Rust 版本政策
此 crate 支持的最低 `rustc` 版本是 `1.65.0`。
该政策是,使用此 crate所需的最低 Rust 版本可能会在次要版本更新中增加。例如,如果 regex 1.0 需要 Rust 1.20.0,那么对于所有 `z` 值,regex 1.0.z 也将需要 Rust 1.20.0 或更新版本。但是,对于 `y > 0` 的 regex 1.y 可能需要更新的 Rust 最低版本。
### 许可证
该项目根据以下任一许可授权:
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) 或 https://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) 或 https://opensource.org/licenses/MIT)
根据您的选择。
`regex-syntax/src/unicode_tables/` 中的数据根据 Unicode 许可协议 ([LICENSE-UNICODE](https://www.unicode.org/copyright.html#License)) 授权。
标签:Regex引擎, Rust, Rust Crate, 可视化界面, 搜索算法, 数据提取, 文本处理, 有限自动机, 模式匹配, 线性时间复杂度, 编程工具, 网络流量审计, 自动化资产收集, 解析库, 软件开发, 远程代码执行, 通知系统