正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。
许多程序设计语言都支持利用正则表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的正则表达式引擎。正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。正则表达式通常缩写成“regex”,单数有regexp、regex,复数有regexps、regexes、regexen。
Rust 中对正则表达式的支持通过 regex crate 提供,我们从验证并提取电子邮件登录信息、从文本提取标签元素唯一的列表、从文本提取电话号码、通过匹配多个正则表达式来筛选日志文件、文本模式替换等几个应用案例对 Rust 的正则表达式处理进行体验。
验证并提取电子邮件登录信息
验证电子邮件地址的格式是否正确,并提取 @ 符号之前的所有内容。
use lazy_static::lazy_static;use regex::Regex;fn extract_login(input: &str) -> Option { lazy_static! { static ref RE: Regex = Regex::new(r"(?x) ^(?P[^@\s]+)@ ([[:word:]]+\.)* [[:word:]]+$ ").unwrap(); } RE.captures(input).and_then(|cap| { cap.name("login").map(|login| login.as_str()) })}fn main() { assert_eq!(extract_login(r"I❤email@example.com"), Some(r"I❤email")); assert_eq!( extract_login(r"sdf+sdsfsd.as.sdsd@jhkk.d.rl"), Some(r"sdf+sdsfsd.as.sdsd") ); assert_eq!(extract_login(r"More@Than@One@at.com"), None); assert_eq!(extract_login(r"Not an email@email"), None);}
从文本提取标签元素唯一的列表
本实例展示从文本中提取、排序和去除标签列表的重复元素。
这里给出的标签正则表达式只捕获以字母开头的拉丁语标签,完整的 twitter 标签正则表达式要复杂得多。
use lazy_static::lazy_static;use regex::Regex;use std::collections::HashSet;fn extract_hashtags(text: &str) -> HashSet { lazy_static! { static ref HASHTAG_REGEX : Regex = Regex::new( r"\#[a-zA-Z][0-9a-zA-Z_]*" ).unwrap(); } HASHTAG_REGEX.find_iter(text).map(|mat| mat.as_str()).collect()}fn main() { let tweet = "Hey #world, I just got my new #dog, say hello to Till. #dog #forever #2 #_ "; let tags = extract_hashtags(tweet); assert!(tags.contains("#dog") && tags.contains("#forever") && tags.contains("#world")); assert_eq!(tags.len(), 3);}
从文本提取电话号码
使用 Regex::captures_iter 处理一个文本字符串,以捕获多个电话号码。这里的例子中是美国电话号码格式。
use error_chain::error_chain;use regex::Regex;use std::fmt;error_chain!{ foreign_links { Regex(regex::Error); Io(std::io::Error); }}struct PhoneNumber<'a> { area: &'a str, exchange: &'a str, subscriber: &'a str,}impl<'a> fmt::Display for PhoneNumbera> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "1 ({}) {}-{}", self.area, self.exchange, self.subscriber) }}fn main() -> Result { let phone_text = " +1 505 881 9292 (v) +1 505 778 2212 (c) +1 505 881 9297 (f) (202) 991 9534 Alex 5553920011 1 (800) 233-2010 1.299.339.1020"; let re = Regex::new( r#"(?x) (?:\+?1)? # 国家代码,可选项 [\s\.]? (([2-9]\d{2})|\(([2-9]\d{2})\)) # 地区代码 [\s\.\-]? ([2-9]\d{2}) # 交换代码 [\s\.\-]? (\d{4}) # 用户号码"#, )?; let phone_numbers = re.captures_iter(phone_text).filter_map(|cap| { let groups = (cap.get(2).or(cap.get(3)), cap.get(4), cap.get(5)); match groups { (Some(area), Some(ext), Some(sub)) => Some(PhoneNumber { area: area.as_str(), exchange: ext.as_str(), subscriber: sub.as_str(), }), _ => None, } }); assert_eq!( phone_numbers.map(|m| m.to_string()).collect::>(), vec![ "1 (505) 881-9292", "1 (505) 778-2212", "1 (505) 881-9297", "1 (202) 991-9534", "1 (555) 392-0011", "1 (800) 233-2010", "1 (299) 339-1020", ] ); Ok(())}
以上实例代码都是完整的、可独立运行的程序,因此你可以直接复制它们到自己的项目中进行试验。
如果希望从头了解如何运行上述实例代码,请参考《Rust 实践指南》中关于本书-如何使用本书实例部分。也可以复制链接:http://budshome.com/rust-cookbook/about.html 点击阅读原文进行更详细的学习。