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 在 文本处理 中
134 每月下载量
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]。
正则表达式文字示例
- 一个简单的模式:
r#"/ab+c/"#
- 一个正则表达式并集文字:
r#"[/(?i)ab+c/,/(?u)\s{2}D+/]"#
- 正则表达式序列字面量:
r#"<(?i)ab+c/,/(?u)\s{2}D+/>"#
- 另一个正则表达式序列字面量:
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_from
、crate::XRegex::from_str
或 crate::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"));
正则表达式字面量的转换
crate::util::delimit
和crate::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);
crate::assembly::into_reu
和crate::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