正则表达式
电子邮件地址提取登录名,并验证
验证电子邮件地址的格式是否正确,并提取@
符号之前的所有内容。
#[macro_use] extern crate lazy_static; extern crate regex; 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(); } 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 #标签 正则式更复杂。
extern crate regex; #[macro_use] extern crate lazy_static; use regex::Regex; use std::collections::HashSet; fn extract_hashtags(text: &str) -> HashSet<&str> { 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
捕捉多个电话号码。这里的示例是,美国会议电话号码。
# #[macro_use] # extern crate error_chain; extern crate regex; 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 PhoneNumber<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "1 ({}) {}-{}", self.area, self.exchange, self.subscriber) } } fn run() -> 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)? # Country Code Optional [\s\.]? (([2-9]\d{2})|\(([2-9]\d{2})\)) # Area Code [\s\.\-]? ([2-9]\d{2}) # Exchange Code [\s\.\-]? (\d{4}) # Subscriber Number"#, )?; 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<_>>(), 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(()) } # # quick_main!(run);
通过匹配多个正则表达式,筛选日志文件
读取名为application.log
的文件,并且只输出包含“version x.x.x”、或一些 IP 地址跟着端口 443(例如“192.168.0.1:443”)或特殊 warning 的那些行。
一个regex::RegexSetBuilder
组成一个regex::RegexSet
。 因为反斜杠在正则表达式中,非常常见,所以使用原始字符串文本能让它们更具可读性。
# #[macro_use] # extern crate error_chain; extern crate regex; use std::fs::File; use std::io::{BufReader, BufRead}; use regex::RegexSetBuilder; # error_chain! { # foreign_links { # Io(std::io::Error); # Regex(regex::Error); # } # } # fn run() -> Result<()> { let log_path = "application.log"; let buffered = BufReader::new(File::open(log_path)?); let set = RegexSetBuilder::new(&[ r#"version "\d\.\d\.\d""#, r#"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:443"#, r#"warning.*timeout expired"#, ]).case_insensitive(true) .build()?; buffered .lines() .filter_map(|line| line.ok()) .filter(|line| set.is_match(line.as_str())) .for_each(|x| println!("{}", x)); Ok(()) } # # quick_main!(run);
将一个文本模式的所有出现项,替换为另一个模式。
将所有出现的标准 ISO 8601 YYY-MM-DD 的日期模式,替换等效的带斜线美式英文日期。例如2013-01-15
变成01/15/2013
.
方法Regex::replace_all
会替换整个正则式的所有出现项。&str
实现了Replacer
trait,这允许类似$abcde
这样的变量,去引用在搜索的正则式中,相应的命名捕获组(?P<abcde>REGEX)
。见替换字符串语法示例,和转义的细节。
extern crate regex; #[macro_use] extern crate lazy_static; use std::borrow::Cow; use regex::Regex; fn reformat_dates(before: &str) -> Cow<str> { lazy_static! { static ref ISO8601_DATE_REGEX : Regex = Regex::new( r"(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})" ).unwrap(); } ISO8601_DATE_REGEX.replace_all(before, "$m/$d/$y") } fn main() { let before = "2012-03-14, 2013-01-15 and 2014-07-05"; let after = reformat_dates(before); assert_eq!(after, "03/14/2012, 01/15/2013 and 07/05/2014"); }