使用:在
Cargo.toml
文件中
[dependencies]
下添加
regex
其他使用示例: https://rust-cookbook.budshome.com/text/regex.html
一、简单示例
(来自regex文档)
use regex::Regex;
// 常规日期查找
let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
assert!(re.is_match("2014-01-01"));
// 表达式反复与搜索字符串进行匹配
let re = Regex::new(r"(\d{4})-(\d{2})-(\d{2})").unwrap();
let text = "2012-03-14, 2013-01-01 and 2014-07-05";
for cap in re.captures_iter(text) {
println!("Month: {} Day: {} Year: {}", &cap[2], &cap[3], &cap[1]);
}
/* Output:
* Month: 03 Day: 14 Year: 2012
* Month: 01 Day: 01 Year: 2013
* Month: 07 Day: 05 Year: 2014
*/
// 替换命名捕获
let re = Regex::new(r"(?x)
(?P<y>\d{4}) # the year
-
(?P<m>\d{2}) # the month
-
(?P<d>\d{2}) # the day
").unwrap();
let before = "2012-03-14, 2013-01-01 and 2014-07-05";
let after = re.replace_all(before, "$m/$d/$y");
assert_eq!(after, "03/14/2012, 01/01/2013 and 07/05/2014");
// 同时匹配多个常规表达式
let set = RegexSet::new(&[
r"\w+",
r"\d+",
r"\pL+",
r"foo",
r"bar",
r"barfoo",
r"foobar",
]).unwrap();
// 迭代并收集所有匹配项
let matches: Vec<_> = set.matches("foobar").into_iter().collect();
assert_eq!(matches, vec![0, 2, 3, 4, 6]);
// 您还可以测试特定正则表达式是否匹配:
let matches = set.matches("foobar");
assert!(!matches.matched(5));
assert!(matches.matched(6));
use lazy_static::lazy_static;
use regex::Regex;
fn extract_login(input: &str) -> Option<&str> {
lazy_static! {
static ref RE: Regex = Regex::new(r"(?x)
^(?P<login>[^@\s]+)@
([[:word:]]+\.)*
[[:word:]]+$
").unwrap();
}
// 【一】?P<login> :命名捕获组:login
// 【二】[^@\s]+ :不出现:@、空格
// 【三】[[:word:]]+ :匹配[0-9a-zA-Z_]+
// 第一行:命名捕获组,@前面不允许出现:@、空格(即@不重复,用户名不允许有空格)
RE.captures(input).and_then(|cap|{
cap.name("login").map(|login|login.as_str())
})
}
fn main() {
let text_01 = r"I❤email@example.com";
let text_02 = r"sdf+sdsfsd.as.sdsd@jhkk.d.rl";
let text_03 = r"Not_an_email@email";
println!("text_01= {}",extract_login(&text_01).unwrap());
println!("text_02= {}",extract_login(&text_02).unwrap());
println!("text_03= {}",extract_login(&text_03).unwrap());
assert_eq!(extract_login(r"More@Than@One@at.com"), None);
assert_eq!(extract_login(r"Not an email@email"), None);
}
二、正则语法
此板条箱中支持的语法记录如下。正则语法
请注意,常规表达解析器和抽象语法暴露在一个单独的箱子中 regex-syntax
.
匹配(一个)字符
. # 除新行以外的任何字符(包括带有s标志的新行)
\d # 数字 (\p{Nd})
\D # 非数字
\pN # 单字母名称Unicode字符类
\PN # Negated(非) 单字母名称Unicode字符类
\p{Greek} # Unicode字符类(常规类别或脚本)
\P{Greek} # negated(非) Unicode字符类(常规类别或脚本)
[xyz] # 匹配x、y或z(并集)的字符类。
[^xyz] # 匹配 除x、y和z以外的 任何字符的字符类。
[a-z] # 匹配A-z范围内任何字符的字符类。
[[:alpha:]] # ASCII 字符类 ([A-Za-z])
[[:^alpha:]] # Negated(非) ASCII 字符类 ([^A-Za-z])
[x[^xyz]] # 嵌套/分组字符类(匹配除y和z以外的任何字符)
[a-y&&xyz] # 交集(匹配x或y)
[0-9&&[^4]] # 使用交集和求反的减法(匹配0-9,4除外)
[0-9--4] # 直接减法 (匹配0-9,4除外)
[a-g~~b-h] # 对称差异(范围异或)(仅匹配“a”和“h”)
[\[\]] # 字符类中的转义(匹配[ 或 ])
任何命名的字符类都可能出现在括号字符类中。例如,匹配任何希腊语或 ASCII 数字。 匹配希腊字母。[...]
,[\p{Greek}[:digit:]]
,[\p{Greek}&&\pL]
字符类中的优先级,从最绑定到最少:
- 范围:
a-cd
==[a-c]d
- 并集:
ab&&bc
==[ab]&&[bc]
- 交集:
^a-z&&b
==^[a-z&&b]
- 否定
复合
xy 串联(x后跟y)
x|y 交替 (x or y, 优先 x)
重复项, 空匹配
x* # zero or more of x (greedy) [0-n]个x (贪婪)
x+ # one or more of x (greedy) [1-n]个x (贪婪)
x? # zero or one of x (greedy) [0-1]个x (贪婪)
x*? # zero or more of x (ungreedy/lazy) [0-n]个x (非贪婪/懒惰)
x+? # one or more of x (ungreedy/lazy) [1-n]个x (非贪婪/懒惰)
x?? # zero or one of x (ungreedy/lazy) [0-1]个x (非贪婪/懒惰)
x{n,m} # at least n x and at most m x (greedy)
x{n,} # at least n x (greedy)
x{n} # exactly n x
x{n,m}? # at least n x and at most m x (ungreedy/lazy)
x{n,}? # at least n x (ungreedy/lazy)
x{n}? # exactly n x
^ # 文本的开头(或多行模式下的行首)
$ # 文本的结尾(或多行模式下的行尾)
\A # 仅文本开头(即使启用多行模式)
\z # 仅文本结尾(即使启用多行模式)
\b # Unicode单词边界(一侧是\w,另一侧是\W、\A或\z)
\B # 非Unicode单词边界
分组和标记
(exp) 编号捕获组(用括号开头索引)
(?P<name>exp) 命名(或编号)捕获组 (允许的字符: [_0-9a-zA-Z.\[\]])
(?:exp) 非捕获组 non-capturing group
(?flags) 在当前组中设置标志
(?flags:exp) 为exp(非捕获)设置标志 set flags for exp (non-capturing)
标志各为一个字符。例如,设置标志并清除标志。多个标志可以同时设置或清除:设置和标记,并设置标志并清除标志。(?x)
,x
,(?-x)
,x
,(?xy)
,x
,y
,(?x-y)
,x
,y
除非另有说明,否则所有标志将默认禁用。它们是:
i # 不区分大小写:字母匹配大小写
m # 多行模式:^和$匹配行首/行尾
s # 允许 . 匹配 \n
U # 交换 x* 和 x*?
u # Unicode支持(默认启用)
x # 忽略空白并允许行注释(以“#”开头)
标志可以在模式内切换。下面是一个示例,该示例对第一部分案例的大小写不敏感,但第二部分案例的大小写敏感:
let re = Regex::new(r"(?i)a+(?-i)b+").unwrap();
let cap = re.captures("AaAaAbbBBBb").unwrap();
assert_eq!(&cap[0], "AaAaAbb");
请注意,匹配或,但唯一匹配。a+
,a
,A
,b+
,b
多行模式意味着不再仅在输入的开头/结束匹配,而是在输入的开头/结束匹配:^
,$
let re = Regex::new(r"(?m)^line \d+").unwrap();
let m = re.find("line one\nline 2\n").unwrap();
assert_eq!(m.as_str(), "line 2");
请注意,匹配后的新行,即使在输入的末尾:^
let re = Regex::new(r"(?m)^").unwrap();
let m = re.find_iter("test\n").last().unwrap();
assert_eq!((m.start(), m.end()), (5, 5));
下面是一个使用 ASCII 单词边界而不是 Unicode 单词边界的示例:
let re = Regex::new(r"(?-u:\b).+(?-u:\b)").unwrap();
let cap = re.captures("$$abc$$").unwrap();
assert_eq!(&cap[0], "abc");
Escape-sequences
\* # literal *, 适用于任何标点字符: \.+*?()|[]{}^$
\a # bell (\x07)
\f # form feed (\x0C)
\t # horizontal tab
\n # new line
\r # carriage return
\v # vertical tab (\x0B)
\123 # 八进制字符代码(最多三位数)(启用时)
\x7F # 十六进制字符代码(精确两位)
\x{10FFFF} # 与Unicode码位对应的任何十六进制字符代码
\u007F # 十六进制字符代码(正好四位数)
\u{7F} # 与Unicode码位对应的任何十六进制字符代码
\U0000007F # 十六进制字符代码(正好八位数字)
\U{7F} # 与Unicode码位对应的任何十六进制字符代码
Perl & ASCII 字符类
\d # digit (\p{Nd})
\D # not digit
\s # whitespace (\p{White_Space})
\S # not whitespace
\w # word character (\p{Alphabetic} + \p{M} + \d + \p{Pc} + \p{Join_Control})
\W # not word character
[[:alnum:]] # alphanumeric ([0-9A-Za-z])
[[:alpha:]] # alphabetic ([A-Za-z])
[[:ascii:]] # ASCII ([\x00-\x7F])
[[:blank:]] # blank ([\t ])
[[:cntrl:]] # control ([\x00-\x1F\x7F])
[[:digit:]] # digits ([0-9])
[[:graph:]] # graphical ([!-~])
[[:lower:]] # lower case ([a-z])
[[:print:]] # printable ([ -~]) 可打印
[[:punct:]] # punctuation ([!-/:-@\[-`{-~]) 标点符号
[[:space:]] # whitespace ([\t\n\v\f\r ]) 空白
[[:upper:]] # upper case ([A-Z])
[[:word:]] # word characters ([0-9A-Za-z_])
[[:xdigit:]] # hex digit ([0-9A-Fa-f]) 十六进制数字