1. 正则表达式
需要安装regex
库和lazy_static
库,可通过cargo add regex
和cargo add lazy_static
命令安装
[dependencies] lazy_static = "1.4.0" regex = "1.8.1"
|
1.1 验证并提取电子邮件登录信息
验证电子邮件地址的格式是否正确,并提取 @
符号之前的所有内容。
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(); } 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"唐三藏@tang.da"), Some(r"唐三藏")); assert_eq!(extract_login(r"More@Than@One@at.com"), None); assert_eq!(extract_login(r"Not an email@email"), None); }
|
1.2 从文本提取标签元素唯一的列表
展示从文本中提取、排序和去除标签列表的重复元素。这里给出的标签正则表达式只捕获以字母开头的拉丁语标签,完整的 twitter 标签正则表达式要复杂得多。
use lazy_static::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); }
|
1.3 从文本提取电话号码
需要安装error-chain
库,可通过cargo add error-chain
命令安装
[dependencies] error-chain = "0.12.4" regex = "1.8.1"
|
使用 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 PhoneNumber<'a> { 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<_>>(), 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(()) }
|
1.4 通过匹配多个正则表达式来筛选日志文件
读取名为 application.log
(可以根据以下输出的内容自建) 的文件,并且只输出包含下列内容的行:“version X.X.X
”、端口为 443
的 IP 地址(如 “192.168.0.1:443
”)、特定警告。正则表达集构造器 regex::RegexSetBuilder
构建了正则表达式集 regex::RegexSet
。由于反斜杠在正则表达式中非常常见,因此使用原始字符串字面量可以使它们更具可读性。
use error_chain::error_chain;
use std::fs::File; use std::io::{BufReader, BufRead}; use regex::RegexSetBuilder;
error_chain! { foreign_links { Io(std::io::Error); Regex(regex::Error); } }
fn main() -> 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(()) }
|
fasfsafad version 1.2.1 afsadfwew 163.211.115.56:443 asfasdfsfsdfas warning fasfsafad version 1.2.2 afsadfwew 63.211.115.56:443 asfasdfsfsdfas fasfsafad version 1.2.3 afsadfwew 13.211.115.56:443 asfasdfsfsdfas timeout expired
|
1.5 文本模式替换
将所有出现的国际标准 ISO 8601
日期模式 YYYY-MM-DD
替换为美式英语及中式日期模式。例如: 2013-01-15
替换为 01/15/2013
。Regex::replace_all
方法将替换整个正则表示匹配的所有内容。&str
实现了 Replacer
trait,它允许类似 $abcde
的变量引用相应的搜索匹配模式(search regex)中的命名捕获组 (?P<abcde>REGEX
)。有关示例和转义的详细信息,请参阅替换字符串语法。
use lazy_static::lazy_static;
use regex::Regex; use std::borrow::Cow;
fn reformat_dates_us(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 reformat_dates_cn(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, "$y年$m月$d日") }
fn main() { let before = "2012-03-14, 2013-01-15 and 2014-07-05"; let after_us = reformat_dates_us(before); assert_eq!(after_us, "03/14/2012, 01/15/2013 and 07/05/2014"); let after_cn = reformat_dates_cn(before); assert_eq!( after_cn, "2012年03月14日, 2013年01月15日 and 2014年07月05日" ); }
|
2. 字符串解析
2.1 收集 Unicode
字符
需要安装unicode-segmentation
库,可通过cargo add unicode-segmentation
命令安装
[dependencies] unicode-segmentation = "1.10.1"
|
使用 unicode-segmentation
crate 中的 UnicodeSegmentation::graphemes
函数,从 UTF-8
字符串中收集个别的 Unicode
字符。
use unicode_segmentation::UnicodeSegmentation;
fn main() { let name = "José Guimarães 大胃王\r\n"; let graphemes = UnicodeSegmentation::graphemes(name, true).collect::<Vec<&str>>(); println!("{:?}", graphemes); assert_eq!(graphemes[3], "é"); }
|
2.2 自定义结构体并实现 FromStr
trait
实例中,创建一个自定义结构体 RGB
并实现 FromStr
trait,以将提供的颜色十六进制代码转换为其 RGB
颜色代码。
use std::str::FromStr;
#[derive(Debug, PartialEq)] struct RGB { r: u8, g: u8, b: u8, }
impl FromStr for RGB { type Err = std::num::ParseIntError;
fn from_str(hex_code: &str) -> Result<Self, Self::Err> { let r: u8 = u8::from_str_radix(&hex_code[1..3], 16)?; let g: u8 = u8::from_str_radix(&hex_code[3..5], 16)?; let b: u8 = u8::from_str_radix(&hex_code[5..7], 16)?;
Ok(RGB { r, g, b }) } }
fn main() { let code: &str = &r"#fa7268"; match RGB::from_str(code) { Ok(rgb) => { println!(r"RGB颜色代码是: R: {} G: {} B: {}", rgb.r, rgb.g, rgb.b); } Err(_) => { println!("{} 不是有效的颜色十六进制代码!", code); } }
assert_eq!( RGB::from_str(&r"#fa7268").unwrap(), RGB { r: 250, g: 114, b: 104 } ); }
|
RGB颜色代码是: R: 250 G: 114 B: 104
|