15 个版本 (稳定版)

1.4.5 2024年3月6日
1.4.4 2023年8月24日
1.4.2 2023年7月26日
1.4.1 2022年10月21日
0.2.0 2019年10月19日

#4 in #expression-parser

Download history 207/week @ 2024-04-22 184/week @ 2024-04-29 144/week @ 2024-05-06 172/week @ 2024-05-13 158/week @ 2024-05-20 148/week @ 2024-05-27 182/week @ 2024-06-03 149/week @ 2024-06-10 123/week @ 2024-06-17 143/week @ 2024-06-24 151/week @ 2024-07-01 125/week @ 2024-07-08 133/week @ 2024-07-15 136/week @ 2024-07-22 114/week @ 2024-07-29 84/week @ 2024-08-05

每月491次下载
qsv 中使用

Apache-2.0

640KB
4K SLoC

grex


rust build status python build status docs.rs codecov dependency status demo

downloads crates.io lib.rs supported Python versions pypi license

Linux 64-bit Download Linux ARM64 Download

MacOS 64-bit Download MacOS ARM64 Download

Windows 64-bit Download Windows ARM64 Download


grex demo


1. 这个工具做什么?

grex 既是库又是命令行工具,旨在简化创建正则表达式这一通常复杂且繁琐的任务。它通过从用户提供的测试案例中自动生成单个正则表达式来实现这一点。生成的表达式将保证匹配它所生成的测试案例。

这个项目最初是 Devon Govett 编写的 JavaScript 工具 regexgen 的 Rust 版本。尽管可以添加很多其他有用的功能,但它的开发似乎已经停止了几年。现在计划将这些新功能添加到 grex 中,因为 Rust 在命令行工具方面表现出色。grex 提供了所有 regexgen 提供的功能,还有更多。

这个项目的理念是默认生成最具体的正则表达式,它只与给定的输入完全匹配,而不匹配其他任何内容。通过使用命令行标志(在 CLI 工具中)或预处理方法(在库中),可以创建更通用的表达式。

生成的表达式是兼容 Perl 的正则表达式,也兼容 Rust 的 regex crate 中的正则表达式解析器。迄今为止,尚未测试其他正则表达式解析器或相应编程语言的库,但它们应该也与大多数兼容。

2. 我还需要学习编写正则表达式吗?

当然需要! 使用标准设置,grex 生成的正则表达式将保证只匹配输入的测试案例,而不匹配其他任何内容。这已经通过 属性测试 验证。然而,如果启用了转换为缩写字符类(如 \w)的转换,生成的正则表达式将匹配更广泛的测试案例。了解这种转换的后果对于找到适合您业务领域的正确正则表达式至关重要。

grex 使用一种算法,尝试为给定的测试用例找到最短的可能的正则表达式。然而,生成的表达式通常仍然比所需的更长或更复杂。在这种情况下,只有通过手动操作才能创建更紧凑或更优雅的正则表达式。此外,每个正则表达式引擎都有不同的内置优化。 grex 对这些一无所知,因此无法针对特定引擎优化其正则表达式。

因此,请学习如何编写正则表达式! 目前 grex 的最佳用途是找到一个初始正确的正则表达式,如果可能进行进一步优化,则应手动检查。

3. 当前功能

  • 字面量
  • 字符类
  • 检测常见的前缀和后缀
  • 检测重复的子字符串,并将其转换为 {min,max} 量词表示法
  • 使用 | 操作符进行选择
  • 使用 ? 量词进行可选性
  • 转义非 ASCII 字符,可选地将天顶字码点转换为代理对
  • 区分大小写或大小写不敏感匹配
  • 捕获组或非捕获组
  • 可选锚点 ^$
  • 完全符合 Unicode 标准版本 15.0
  • 完全兼容 regex 包 1.9.0+
  • 正确处理由多个 Unicode 符号组成的图形符号
  • 从命令行或文件读取输入字符串
  • 在可选的详细模式下,通过缩进来生成更易读的表达式
  • 在支持的终端中,可选语法高亮以获得更好的输出

4. 如何安装?

4.1 命令行工具

您可以从上面下载适用于您平台的独立可执行文件并将其放置在您选择的位置。或者,在软件包管理器中提供了预编译的 64 位二进制文件,包括 Scoop(Windows),Homebrew(macOS 和 Linux),MacPorts(macOS),以及 Huber(macOS、Linux 和 Windows)。 Raúl Piracés 贡献了一个 Chocolatey Windows 包

grex 还托管在 crates.io,官方 Rust 包注册处。如果您是 Rust 开发者并且已经安装了 Rust 工具链,您可以使用 Rust 包管理器 cargo 从源代码编译并安装。因此,您的安装选项总结如下

( brew | cargo | choco | huber | port | scoop ) install grex

4.2 库

要使用 grex 作为库,只需将其添加到您的 Cargo.toml 文件中即可

[dependencies]
grex = { version = "1.4.5", default-features = false }

依赖项 clap 仅用于命令行工具。通过禁用默认功能,防止库中下载和编译 clap。

5. 如何使用?

有关可用设置的详细说明请参阅 库部分。所有设置都可以自由组合。

5.1 命令行工具

测试用例可以通过直接传递(grex a b c)或从文件中传递(grex -f test_cases.txt)。grex 还可以从 Unix 管道接收输入,例如 cat test_cases.txt | grex -

以下表格显示了所有可用的标志和选项

$ grex -h

grex 1.4.5
© 2019-today Peter M. Stahl <[email protected]>
Licensed under the Apache License, Version 2.0
Downloadable from https://crates.io/crates/grex
Source code at https://github.com/pemistahl/grex

grex generates regular expressions from user-provided test cases.

Usage: grex [OPTIONS] {INPUT...|--file <FILE>}

Input:
  [INPUT]...         One or more test cases separated by blank space
  -f, --file <FILE>  Reads test cases on separate lines from a file

Digit Options:
  -d, --digits      Converts any Unicode decimal digit to \d
  -D, --non-digits  Converts any character which is not a Unicode decimal digit to \D

Whitespace Options:
  -s, --spaces      Converts any Unicode whitespace character to \s
  -S, --non-spaces  Converts any character which is not a Unicode whitespace character to \S

Word Options:
  -w, --words      Converts any Unicode word character to \w
  -W, --non-words  Converts any character which is not a Unicode word character to \W

Escaping Options:
  -e, --escape           Replaces all non-ASCII characters with unicode escape sequences
      --with-surrogates  Converts astral code points to surrogate pairs if --escape is set

Repetition Options:
  -r, --repetitions
          Detects repeated non-overlapping substrings and converts them to {min,max} quantifier
          notation
      --min-repetitions <QUANTITY>
          Specifies the minimum quantity of substring repetitions to be converted if --repetitions
          is set [default: 1]
      --min-substring-length <LENGTH>
          Specifies the minimum length a repeated substring must have in order to be converted if
          --repetitions is set [default: 1]

Anchor Options:
      --no-start-anchor  Removes the caret anchor `^` from the resulting regular expression
      --no-end-anchor    Removes the dollar sign anchor `$` from the resulting regular expression
      --no-anchors       Removes the caret and dollar sign anchors from the resulting regular
                         expression

Display Options:
  -x, --verbose   Produces a nicer-looking regular expression in verbose mode
  -c, --colorize  Provides syntax highlighting for the resulting regular expression

Miscellaneous Options:
  -i, --ignore-case     Performs case-insensitive matching, letters match both upper and lower case
  -g, --capture-groups  Replaces non-capturing groups with capturing ones
  -h, --help            Prints help information
  -v, --version         Prints version information

 

5.2 库

5.2.1 默认设置

测试用例可以通过RegExpBuilder::from()从集合中传递,或者通过RegExpBuilder::from_file()从文件中传递。如果从文件中读取,每个测试用例必须单独一行。行可以以换行符\n或回车换行符\r\n结束。

use grex::RegExpBuilder;

let regexp = RegExpBuilder::from(&["a", "aa", "aaa"]).build();
assert_eq!(regexp, "^a(?:aa?)?$");

5.2.2 转换为字符类

use grex::RegExpBuilder;

let regexp = RegExpBuilder::from(&["a", "aa", "123"])
    .with_conversion_of_digits()
    .with_conversion_of_words()
    .build();
assert_eq!(regexp, "^(\\d\\d\\d|\\w(?:\\w)?)$");

5.2.3 转换重复的子串

use grex::RegExpBuilder;

let regexp = RegExpBuilder::from(&["aa", "bcbc", "defdefdef"])
    .with_conversion_of_repetitions()
    .build();
assert_eq!(regexp, "^(?:a{2}|(?:bc){2}|(?:def){3})$");

默认情况下,grex会以这种方式转换每个至少包含一个字符且至少重复一次的子串。如果您喜欢,可以自定义这两个参数。

在下面的示例中,测试用例aa不会被转换为a{2},因为重复的子串a的长度为1,但最小子串长度已被设置为2。

use grex::RegExpBuilder;

let regexp = RegExpBuilder::from(&["aa", "bcbc", "defdefdef"])
    .with_conversion_of_repetitions()
    .with_minimum_substring_length(2)
    .build();
assert_eq!(regexp, "^(?:aa|(?:bc){2}|(?:def){3})$");

在下一个示例中,设置最小重复次数为2,只有测试用例defdefdef会被转换,因为它是唯一重复两次的。

use grex::RegExpBuilder;

let regexp = RegExpBuilder::from(&["aa", "bcbc", "defdefdef"])
    .with_conversion_of_repetitions()
    .with_minimum_repetitions(2)
    .build();
assert_eq!(regexp, "^(?:bcbc|aa|(?:def){3})$");

5.2.4 转义非ASCII字符

use grex::RegExpBuilder;

let regexp = RegExpBuilder::from(&["You smell like 💩."])
    .with_escaping_of_non_ascii_chars(false)
    .build();
assert_eq!(regexp, "^You smell like \\u{1f4a9}\\.$");

旧版本的JavaScript不支持天体代码平面的Unicode转义序列(范围U+010000U+10FFFF)。为了在JavaScript正则表达式中支持这些符号,需要进行代理对转换。有关更多信息,请参阅这里

use grex::RegExpBuilder;

let regexp = RegExpBuilder::from(&["You smell like 💩."])
    .with_escaped_non_ascii_chars(true)
    .build();
assert_eq!(regexp, "^You smell like \\u{d83d}\\u{dca9}\\.$");

5.2.5 不区分大小写的匹配

默认情况下,grex生成的正则表达式是区分大小写的。可以通过以下方式启用不区分大小写的匹配

use grex::RegExpBuilder;

let regexp = RegExpBuilder::from(&["big", "BIGGER"])
    .with_case_insensitive_matching()
    .build();
assert_eq!(regexp, "(?i)^big(?:ger)?$");

5.2.6 捕获组

默认情况下使用非捕获组。在之前的示例中扩展,您可以选择使用捕获组。

use grex::RegExpBuilder;

let regexp = RegExpBuilder::from(&["big", "BIGGER"])
    .with_case_insensitive_matching()
    .with_capturing_groups()
    .build();
assert_eq!(regexp, "(?i)^big(ger)?$");

5.2.7 详细模式

如果您发现生成的正则表达式难以阅读,可以启用详细模式。表达式随后会被放在多行中,并缩进来使其更易于阅读。

use grex::RegExpBuilder;
use indoc::indoc;

let regexp = RegExpBuilder::from(&["a", "b", "bcd"])
    .with_verbose_mode()
    .build();

assert_eq!(regexp, indoc!(
    r#"
    (?x)
    ^
      (?:
        b
        (?:
          cd
        )?
        |
        a
      )
    $"#
));

5.2.8 禁用锚点

默认情况下,锚点^$被放置在每个生成的正则表达式周围,以确保它只匹配作为输入提供的测试用例。然而,通常情况下,人们希望将生成的模式作为更大的模式的一部分使用。为此,可以禁用锚点,可以单独禁用它们,也可以同时禁用它们。

use grex::RegExpBuilder;

let regexp = RegExpBuilder::from(&["a", "aa", "aaa"])
    .without_anchors()
    .build();
assert_eq!(regexp, "a(?:aa?)?");

5.3 示例

以下示例展示了各种支持的正则表达式语法特性

$ grex a b c
^[a-c]$

$ grex a c d e f
^[ac-f]$

$ grex a b x de
^(?:de|[abx])$

$ grex abc bc
^a?bc$

$ grex a b bc
^(?:bc?|a)$

$ grex [a-z]
^\[a\-z\]$

$ grex -r b ba baa baaa
^b(?:a{1,3})?$

$ grex -r b ba baa baaaa
^b(?:a{1,2}|a{4})?$

$ grex y̆ a z
^(?:y̆|[az])$
Note: 
Grapheme y̆ consists of two Unicode symbols:
U+0079 (Latin Small Letter Y)
U+0306 (Combining Breve)

$ grex "I ♥ cake" "I ♥ cookies"
^I ♥ c(?:ookies|ake)$
Note:
Input containing blank space must be 
surrounded by quotation marks.

字符串"I ♥♥♥ 36 and ٣ and 💩💩."作为以下示例的输入,使用命令行符号

$ grex <INPUT>
^I ♥♥♥ 36 and ٣ and 💩💩\.$

$ grex -e <INPUT>
^I \u{2665}\u{2665}\u{2665} 36 and \u{663} and \u{1f4a9}\u{1f4a9}\.$

$ grex -e --with-surrogates <INPUT>
^I \u{2665}\u{2665}\u{2665} 36 and \u{663} and \u{d83d}\u{dca9}\u{d83d}\u{dca9}\.$

$ grex -d <INPUT>
^I ♥♥♥ \d\d and \d and 💩💩\.$

$ grex -s <INPUT>
^I\s♥♥♥\s36\sand\s٣\sand\s💩💩\.$

$ grex -w <INPUT>
^\w ♥♥♥ \w\w \w\w\w \w \w\w\w 💩💩\.$

$ grex -D <INPUT>
^\D\D\D\D\D\D36\D\D\D\D\D٣\D\D\D\D\D\D\D\D$

$ grex -S <INPUT>
^\S \S\S\S \S\S \S\S\S \S \S\S\S \S\S\S$

$ grex -dsw <INPUT>
^\w\s♥♥♥\s\d\d\s\w\w\w\s\d\s\w\w\w\s💩💩\.$

$ grex -dswW <INPUT>
^\w\s\W\W\W\s\d\d\s\w\w\w\s\d\s\w\w\w\s\W\W\W$

$ grex -r <INPUT>
^I{3} 36 and ٣ and 💩{2}\.$

$ grex -er <INPUT>
^I \u{2665}{3} 36 and \u{663} and \u{1f4a9}{2}\.$

$ grex -er --with-surrogates <INPUT>
^I \u{2665}{3} 36 and \u{663} and (?:\u{d83d}\u{dca9}){2}\.$

$ grex -dgr <INPUT>
^I{3} \d(\d and ){2}💩{2}\.$

$ grex -rs <INPUT>
^I\s♥{3}\s36\sand\s٣\sand\s💩{2}\.$

$ grex -rw <INPUT>
^\w{3} \w(?:\w \w{3} ){2}💩{2}\.$

$ grex -Dr <INPUT>
^\D{6}36\D{5}٣\D{8}$

$ grex -rS <INPUT>
^\S \S(?:\S{2} ){2}\S{3} \S \S{3} \S{3}$

$ grex -rW <INPUT>
^I\W{5}36\Wand\W٣\Wand\W{4}$

$ grex -drsw <INPUT>
^\w\s♥{3}\s\d(?:\d\s\w{3}\s){2}💩{2}\.$

$ grex -drswW <INPUT>
^\w\s\W{3}\s\d(?:\d\s\w{3}\s){2}\W{3}$

6. 如何构建?

为了自己构建源代码,您需要在您的机器上安装稳定的Rust工具链,以便可以使用cargo,Rust包管理器。请注意:需要Rust >= 1.70.0来构建CLI。对于库部分,Rust < 1.70.0就足够了。

git clone https://github.com/pemistahl/grex.git
cd grex
cargo build

源代码附带了一个庞大的测试套件,包括单元测试、集成测试和属性测试。要运行它们,只需说

cargo test

可以使用以下命令运行测量多个设置性能的基准测试

cargo bench

7. Python 扩展模块

借助 PyO3Maturin,库已被编译为 Python 扩展模块,因此它可以在任何 Python 软件中使用。它可在 Python 包索引 中找到,并可以通过以下方式安装

pip install grex

要自行构建 Python 扩展模块,请创建一个虚拟环境并安装 Maturin

python -m venv /path/to/virtual/environment
source /path/to/virtual/environment/bin/activate
pip install maturin
maturin build

Python 库包含一个名为 RegExpBuilder 的单个类,可以像这样导入

from grex import RegExpBuilder

8. WebAssembly 支持

此库可以编译为 WebAssembly (WASM),这使得您可以在任何基于 JavaScript 的项目中使用 grex,无论是浏览器还是运行在 Node.js 上的后端。

最简单的方法是使用 wasm-pack。安装后,您可以构建以 Web 为目标的库,以便可以直接在浏览器中使用

wasm-pack build --target web

这将在此存储库的顶层创建一个名为 pkg 的目录,其中包含编译后的 wasm 文件以及 JavaScript 和 TypeScript 绑定。在 HTML 文件中,您可以像以下示例那样调用 grex

<script type="module">
    import init, { RegExpBuilder } from "./pkg/grex.js";

    init().then(_ => {
        alert(RegExpBuilder.from(["hello", "world"]).build());
    });
</script>

此外,还有针对 Node.js 和浏览器 Chrome、Firefox 和 Safari 的集成测试。要运行它们,只需说

wasm-pack test --node --headless --chrome --firefox --safari

如果测试在 Safari 中无法启动,您需要先通过运行

sudo safaridriver --enable

wasm-pack 的输出将托管在 单独的存储库 中,这允许添加更多的 JavaScript 相关配置、测试和文档。然后 grex 将添加到 npm 注册表 中,使得在每一个 JavaScript 或 TypeScript 项目中都可以轻松下载和安装。

还有一个 演示网站 可供您试用 grex。

demo website

12. 1.5.0 版本下一步是什么?

  1. 从输入字符串创建一个 确定有限自动机 (DFA)。

  2. 通过应用 Hopcroft 的 DFA 最小化算法,减少了 DFA 中的状态数量和状态之间的转换。

  3. 最小化 DFA 用一组线性方程表示,这些方程用 Brzozowski 的代数方法 求解,得到最终的正则表达式。

13. 1.5.0 版本下一步是什么?

查看 计划中的问题

14. 贡献

如果您想为 grex 做出贡献,我鼓励您这样做。您有没有一些酷功能的想法?或者您至今是否发现了任何错误?请随意打开一个问题或发送一个拉取请求。这非常受欢迎。:-)

依赖项

~6–20MB
~222K SLoC