google/re2

GitHub: google/re2

Google 开源的安全正则表达式库,通过避免回溯保证线性时间复杂度,防止 ReDoS 攻击。

Stars: 9635 | Forks: 1218

# RE2,一个正则表达式库 RE2 是一个高效、规范的 正则表达式库, 自 2006 年以来一直被 Google 和许多其他地方用于生产环境。 _**安全性是 RE2 的首要目标。**_ RE2 的设计和实现有一个明确的目标,即能够 安全地处理来自不可信用户的正则表达式。 它的主要保证之一是匹配时间与输入字符串的长度成线性关系。 它也是在考虑生产环境的基础上编写的: 解析器、编译器和执行引擎通过在可配置的预算内工作来限制其内存使用—— 在耗尽时优雅地失败——并且 它们通过避免递归来防止堆栈溢出。 在所有情况下都比所有其他引擎更快并不是其目标。 虽然 RE2 保证运行时间在渐近上与 输入长度成线性关系,但更复杂的表达式可能会产生更大的常数因子; 更长的表达式会增加安全处理这些表达式所需的开销。 在某种意义上,RE2 是“悲观”的,而回溯引擎是“乐观”的: 回溯引擎按顺序测试每个分支,这使得当第一个分支很常见时速度很快。 相比之下,RE2 并行评估所有分支,避免了最后一个分支的性能惩罚, 但代价是一些开销。这种悲观主义正是 RE2 安全的原因。 实现 Perl、PCRE 和其他引擎提供的所有功能也不是其目标。 作为一项原则,RE2 不支持只存在回溯解决方案的构造。 因此,不支持反向引用和环视断言。 有关更多信息,请参阅 Russ Cox 关于正则表达式理论和实践的文章: * [正则表达式匹配可以简单且快速](https://swtch.com/~rsc/regexp/regexp1.html) * [正则表达式匹配:虚拟机方法](https://swtch.com/~rsc/regexp/regexp2.html) * [野生环境下的正则表达式匹配](https://swtch.com/~rsc/regexp/regexp3.html) ### 语法 在 POSIX 模式下,RE2 接受标准 POSIX (egrep) 语法正则表达式。 在 Perl 模式下,RE2 接受大多数 Perl 运算符。唯一排除的是 那些需要回溯(及其潜在的指数级运行时) 来实现的功能。这包括反向引用(子匹配仍然可以) 和广义断言。 [语法 Wiki 页面](https://github.com/google/re2/wiki/Syntax) 详细记录了支持的 Perl 模式语法。 默认为 Perl 模式。 ### C++ API RE2 的原生语言是 C++,尽管下面列出了[移植和包装器](#ports-and-wrappers)。 #### 匹配接口 有两个基本运算符: `RE2::FullMatch` 要求正则表达式匹配整个输入文本,并且 `RE2::PartialMatch` 查找输入文本子字符串的匹配项, 在 POSIX 模式下返回最左最长匹配,并在 Perl 模式下返回 Perl 会选择的相同匹配。 示例: ``` assert(RE2::FullMatch("hello", "h.*o")) assert(!RE2::FullMatch("hello", "e")) assert(RE2::PartialMatch("hello", "h.*o")) assert(RE2::PartialMatch("hello", "e")) ``` #### 子匹配提取 两个匹配函数都接受额外的参数,子匹配将存储在其中。 参数可以是 `string*`、整数类型或 `absl::string_view*` 类型。 (`absl::string_view` 类型与 `std::string_view` 类型非常相似, 但由于历史原因,RE2 使用前者。) `string_view` 是指向原始输入文本的指针,以及一个计数。 它的行为像字符串,但不自带存储。 就像使用指针一样,使用 `string_view` 时 必须小心,一旦原始文本被删除或超出作用域,就不要再使用它。 示例: ``` // Successful parsing. int i; string s; assert(RE2::FullMatch("ruby:1234", "(\\w+):(\\d+)", &s, &i)); assert(s == "ruby"); assert(i == 1234); // Fails: "ruby" cannot be parsed as an integer. assert(!RE2::FullMatch("ruby", "(.+)", &i)); // Success; does not extract the number. assert(RE2::FullMatch("ruby:1234", "(\\w+):(\\d+)", &s)); // Success; skips NULL argument. assert(RE2::FullMatch("ruby:1234", "(\\w+):(\\d+)", (void*)NULL, &i)); // Fails: integer overflow keeps value from being stored in i. assert(!RE2::FullMatch("ruby:123456789123", "(\\w+):(\\d+)", &s, &i)); ``` #### 预编译正则表达式 上面的示例在每次调用时都重新编译正则表达式。 相反,您可以将其一次编译为 RE2 对象,并在每次调用中重用该对象。 示例: ``` RE2 re("(\\w+):(\\d+)"); assert(re.ok()); // compiled; if not, see re.error(); assert(RE2::FullMatch("ruby:1234", re, &s, &i)); assert(RE2::FullMatch("ruby:1234", re, &s)); assert(RE2::FullMatch("ruby:1234", re, (void*)NULL, &i)); assert(!RE2::FullMatch("ruby:123456789123", re, &s, &i)); ``` #### 选项 构造函数接受一个可选的第二个参数,可以 用来更改 RE2 的默认选项。 例如,`RE2::Quiet` 静默通常在正则表达式解析失败时 打印的错误消息: ``` RE2 re("(ab", RE2::Quiet); // don't write to stderr for parser failure assert(!re.ok()); // can check re.error() for details ``` 其他有用的预定义选项是 `Latin1`(禁用 UTF-8)和 `POSIX` (使用 POSIX 语法和最左最长匹配)。 您还可以声明自己的 `RE2::Options` 对象,然后根据需要对其进行配置。 有关完整的选项集,请参阅[头文件](https://github.com/google/re2/blob/main/re2/re2.h)。 #### Unicode 标准化 RE2 对 Unicode 码点进行操作:它不尝试进行标准化。 例如,正则表达式 /ü/ (U+00FC, 带分音符的 u) 不匹配输入 "ü" (U+0075 U+0308, u 后跟组合分音符)。 标准化是一个漫长而复杂的话题。 如果您需要此类匹配,最简单的解决方案是在使用 RE2 之前 在预处理步骤中对正则表达式和输入进行标准化。 有关一般主题的更多详细信息,请参阅 。 #### 其他技巧和窍门 对于高级用法,例如构建您自己的参数列表, 或将 RE2 用作词法分析器,或解析十六进制、八进制和 C 进制数, 请参阅 [re2.h](https://github.com/google/re2/blob/main/re2/re2.h)。 ### 安装 可以使用 GNU make、CMake 或 Bazel 构建和安装 RE2。 最简单的安装说明是: ``` make make test make benchmark make install make testinstall ``` 构建 RE2 需要 C++17 编译器和 [Abseil](https://github.com/abseil/abseil-cpp) 库。 构建测试和基准测试需要 [GoogleTest](https://github.com/google/googletest) 和 [Benchmark](https://github.com/google/benchmark)。 要获取它们: - Linux:`apt install libabsl-dev libgtest-dev libbenchmark-dev` - macOS:`brew install abseil googletest google-benchmark pkg-config-wrapper` - Windows:`vcpkg install abseil gtest benchmark` \ 或 `vcpkg add port abseil gtest benchmark` 一旦安装了这些,构建过程必须能够找到它们。 如果标准 Makefile 遇到问题,那么切换到 CMake 会有所帮助: ``` rm -rf build cmake -DRE2_TEST=ON -DRE2_BENCHMARK=ON -S . -B build cd build make make test make install ``` 使用 CMake 且启用基准测试时,`make test` 会构建并运行测试二进制文件, 并构建 `regexp_benchmark` 二进制文件,但不会运行它。 如果您根本不需要测试或基准测试,则可以省略相应的 `-D` 参数, 这样您也不需要 GoogleTest 或 Benchmark 依赖项。 另一个有用的选项是 `-DRE2_USE_ICU=ON`,它增加了对 ICU Unicode 库的依赖,但也扩展了 `\p` 和 `\P` 模式中可用的属性名称列表。 CMake 还可用于生成 Visual Studio 和 Xcode 项目,以及 Cygwin、MinGW 和 MSYS makefile。 - Visual Studio 用户:您需要 Visual Studio 2019 或更高版本。 - Cygwin 用户:您必须从 Cygwin 命令行运行 CMake,而不是 Windows 命令行。 如果您将 RE2 添加到您自己的 CMake 项目中, CMake 有两种使用依赖项的方法:`add_subdirectory()`, 即依赖项的**_源代码_**位于您项目的子目录中; 和 `find_package()`,即依赖项的 **_二进制文件_**已在您系统的某处构建和安装。 Abseil 文档在[这里](https://abseil.io/docs/cpp/quickstart-cmake)介绍了前者, 与[这里](https://abseil.io/docs/cpp/tools/cmake-installs)的后者进行了对比。 一旦您让 Abseil 工作,让 RE2 工作将是一个非常类似的过程,并且, 无论哪种方式,`target_link_libraries(… re2::re2)` 都应该直接可用 (Just Work™)。 如果您使用 [Bazel](https://bazel.io),它将为您处理依赖项, 尽管您仍然需要下载 Bazel, 您可以使用 [Bazelisk](https://github.com/bazelbuild/bazelisk) 进行下载。 ``` go install github.com/bazelbuild/bazelisk@latest # 或在 mac 上:brew install bazelisk bazelisk build :all bazelisk test :all ``` 如果您从另一个项目使用 RE2,则需要确保您 至少使用 C++17。 有关示例,请参阅 RE2 [.bazelrc](https://github.com/google/re2/blob/main/.bazelrc) 文件。 ### 移植和包装器 RE2 用 C++ 实现。 官方 Python 包装器[位于 `python` 目录中](https://github.com/google/re2/tree/main/python) 并[在 PyPI 上发布为 `google-re2`](https://pypi.org/project/google-re2/)。 请注意,还有一个 PyPI `re2`,但它不是由 RE2 作者编写的,并且无人维护。请使用 `google-re2`。 还有其他非官方包装器: - C 包装器位于 。 - D 包装器位于 和 [DUB 上](https://code.dlang.org/packages/re2d)。 - Erlang 包装器位于 和 [Hex 上](https://hex.pm/packages/re2)。 - Inferno 包装器位于 。 - Node.js 包装器位于 和 [NPM 上](https://www.npmjs.com/package/re2)。 - OCaml 包装器位于 和 [OPAM 上](https://opam.ocaml.org/packages/re2/)。 - Perl 包装器位于 和 [CPAN 上](https://metacpan.org/pod/re::engine::RE2)。 - R 包装器位于 和 [CRAN 上](https://cran.r-project.org/web/packages/re2/index.html)。 - Ruby 包装器位于 和 RubyGems (rubygems.org)。 - WebAssembly 包装器位于 和 NPM (npmjs.com)。 [RE2J](https://github.com/google/re2j) 是 RE2 C++ 代码到纯 Java 的移植, [RE2JS](https://github.com/le0pard/re2js) 是 RE2J 到 JavaScript 的移植。 [Go `regexp` 包](https://go.dev/pkg/regexp) 和 [Rust `regex` crate](https://docs.rs/regex) 不与 RE2 共享代码,但它们遵循相同的原则, 接受相同的语法,并提供相同的效率保证。 ### 联系 [问题跟踪器](https://github.com/google/re2/issues)是讨论的最佳场所。 有一个[邮件列表](https://groups.google.com/group/re2-dev)用于了解代码更改。 在发送更改之前,请阅读[贡献指南](https://github.com/google/re2/wiki/Contribute)。 请注意,RE2 不使用 GitHub pull requests。
标签:API密钥检测, Bash脚本, C++, Google开源, RE2, ReDoS防护, 多线程安全, 安全, 拒绝服务攻击防御, 数据擦除, 数据清洗, 文本处理, 无回溯, 模式匹配, 正则表达式库, 线性时间复杂度, 网络安全, 自动化资产收集, 解析器, 超时处理, 输入验证, 逆向工具, 隐私保护