#regex #literals #delimiter #string-literal #regular #expression #serialization

regex-literal

以分隔符分隔的正则表达式文字

8 个稳定版本

1.3.1 2024年7月20日
1.3.0 2024年7月9日
1.2.0 2024年5月5日
1.1.1 2024年4月28日
1.0.1 2024年3月17日

148文本处理

Download history 285/week @ 2024-04-26 147/week @ 2024-05-03 6/week @ 2024-05-10 10/week @ 2024-05-17 5/week @ 2024-05-24 1/week @ 2024-05-31 107/week @ 2024-07-05 17/week @ 2024-07-12 123/week @ 2024-07-19 10/week @ 2024-07-26

134 每月下载量

MIT 许可证

76KB
1K SLoC

regex-literal - 被分隔符包围的正则表达式文字

这个crate提供了一种在运行时从分隔文字中快速创建正则表达式Regex和序列ReSequence的方法。其目标是正式化Rust计算中的正则表达式文字。

背景

在Rust参考[^1]中,原始类型(布尔、数值和文本)在源代码编译时都有自己的一组文字表达式,作为单个标记进行评估。但对于正则表达式(简称regex)则不是这样。

在许多实现PCRE库[^2]的脚本语言中,正则表达式模式被一对分隔符包围,例如,JavaScript中的/pattern/im。Rust crate regex-automata中的正则表达式引擎,在构建一个正则表达式时只能接收一个通用的文字(&str)。在Regex::new_many的接口中,需要一个模式字符串数组,因为没有表示复合正则表达式的字符串文字的语法。

功能

该crate提供了以下标点符号的正则表达式和正则表达式集的文字格式

  • //(一对正斜杠)作为包围模式的默认分隔符。

  • [](一对方括号)包含多个模式的并集。

  • <>(一对尖括号)包含正则表达式模式序列和/或模式并集,迭代连续匹配。

  • ,(逗号)作为正则表达式文字之间的分隔符,而在解析时跳过了任何空白Unicode字符[^3]。

正则表达式文字示例

  1. 一个简单的模式:r#"/ab+c/"#
  2. 一个正则表达式并集文字:r#"[/(?i)ab+c/,/(?u)\s{2}D+/]"#
  3. 正则表达式序列字面量:r#"<(?i)ab+c/,/(?u)\s{2}D+/>"#
  4. 另一个正则表达式序列字面量:r#"<[/(?i)ab+c/,/(?u)\s{2}D+/],/\s*\w+/>"#

请注意,[crate::delimited::set_delimiter()] 允许从 crate::delimited::DELIMITER_CHARS 中选择自定义分隔符。此外,crate::util 模块提供了在未分隔和分隔模式之间进行文本转换的公共函数。

从 regex-literal 构建正则表达式结构体

正则表达式结构体可以通过以下方式之一构造:通过 crate::XRegex::try_fromcrate::XRegex::from_strcrate::XRegex::new。前两种使用默认的正则表达式序列字面量分隔符(在 crate::delimited::DELIMITER 中转码为 "/");后者允许自定义分隔符。当用字面量构造 XRegex 时,使用宏 xregex! crate::xregex 是一种简单的方法。

示例

use regex_literal::{XRegex,FromStr,Regex,Match,PatternID,Input,Anchored,xregex};

//example 0: create a XRegex structs from a one-pattern literal by xregex!()
let text = "abc123";
//construct XRegex
let xre = xregex!(r"/^[a-z]+\d{3}$/"); 
// equivalent to the following variances - (1) XRegex::try_from(br"/^[a-z]+\d{3}$/") (2) XRegex::from_str(r"/^[a-z]+\d{3}$/") (3) XRegex::new(r"/^[a-z]+\d{3}$/",b"/")
//get regex reference from XRegex struct
let re = xre.as_regex().unwrap();
//check if the one pattern regex matches with the target text
assert!(re.is_match(text));

//example 1: create a XRegex struct from a one-pattern literal
let text0 = "abc123";
//create one-pattern literal
let re0 = r#"/^[a-z]+\d{3}$/"#;
//construct XRegex
let x = re0.parse::<XRegex>().unwrap();//let x = XRegex::from_str(re0).unwrap();
//get Regex from XRegex struct
let x_one_pattern = x.as_regex().unwrap();
//check if the one pattern regex matches with the target text
assert!(x_one_pattern.is_match(text0));
//find the first match if it exists
let m = x_one_pattern.find(text0);
assert_eq!(m,Some(Match::must(0,0..6)));

//example 2: create a XRegex struct from a one-pattern literal
let text1 = "ABBBC abc123";
let re1 = "!!!!(?i)ab+c!!!!";
//construct XRegex
let y = XRegex::new(re1,b"!!!!").unwrap();
//get Regex from XRegex struct
let y_one_pattern = y.as_regex().unwrap();
// check if this one pattern regex matches with the input
assert!(y_one_pattern.is_match(text1));
//find all non-overlapping leftmost matches
let matches:Vec<Match> = y_one_pattern.find_iter(text1).collect();
assert_eq!(matches,vec![Match::must(0,0..5),Match::must(0,6..9),]);

//example 3: create a XRegex struct from a multiple-pattern literal
let reu = r"[/(?i)ab+c/,/\w+/]";
let mut m1 = XRegex::from_str(reu).unwrap();
//get Regex from XRegex struct
let m_patterns = m1.get_regex().unwrap();
assert!(m_patterns.is_match(text1));
let m_matches:Vec<Match> = m_patterns.find_iter(text1).collect();
assert_eq!(m_matches,vec![Match::must(0,0..5),Match::must(0,6..9),Match::must(1,9..12)]); //non-overlapping leftmost matches

let expected = Some(Match::must(1,0..7));
let input = Input::new("23ABBBC abc&").anchored(Anchored::Pattern(PatternID::must(1)));//choose the specific pattern for input
let n_patterns = XRegex::from_str(reu).unwrap().get_regex().unwrap();
let mut caps = n_patterns.create_captures();
n_patterns.search_captures(&input,&mut caps);
assert_eq!(expected, caps.get_match());

//example 4: create a XRegex struct from a regex sequence literal
let rel = br#"</(?i)ab+c/,/^\w+?\d+$/>"#;
let xre2= XRegex::try_from(&rel[..]).unwrap();
let seq_slice = xre2.as_slice().unwrap();
let child_regex = &seq_slice[1];
assert!(child_regex.is_match("abc333"));

正则表达式字面量的转换

  1. crate::util::delimitcrate::util::undelimit 提供了在未分隔和分隔形式之间进行正则表达式字面量转换的功能。

示例

# use regex_literal::util::{delimit,undelimit};
 
let delimiter = "/";
// a regex literal that includes delimiter(forward slash `/`)
let re1 = r"\d{2}/\d{2}/\d{4}";
let delimited1 = delimit(re1,delimiter);
let string1 = r"/\d{2}\/\d{2}\/\d{4}/";
assert_eq!(&delimited1[..],string1);

let undelimited = undelimit(&delimited1[..],delimiter).unwrap();
assert_eq!(&undelimited[..], re1);

  1. crate::assembly::into_reucrate::assembly::into_res 将模式以默认分隔符注解为正则表达式联合和序列的定界文 literal。请注意,这些转换需要功能 "w"。

示例

# use regex_literal::assembly::into_reu;
let re1 = "(?i)ab+c";
let re2 = r"\w+";
let re_set = [re1,re2];
let reu = into_reu(&re_set);
assert_eq!(reu,r"[/(?i)ab+c/,/\w+/]".to_owned());

致谢

regex-literal 在 Rust crate regex-automata 的正则表达式引擎之上采用了 PCRE-style 定界符。

[^1]: 字面量表达式

[^2]: PCRE 味道

[^3]: 具有属性 White_Space=yes 的 Unicode 字符


查看 crate 版本变更列表,请参阅 CHANGELOG

依赖关系

~1.3–2MB
~25K SLoC