Rust 正则表达式完全指南

Rust 正则表达式完全指南

Rust通过 regex crate提供正则表达式支持。本指南将详细介绍Rust中正则表达式的使用方法、性能优化和最佳实践。

1. 基础知识

1.1 添加依赖

Cargo.toml 中添加:

toml 复制代码
[dependencies]
regex = "1.10.2"

1.2 基本使用

rust 复制代码
use regex::Regex;

fn main() {
    // 创建正则表达式
    let re = Regex::new(r"\d+").unwrap();

    // 基本匹配
    let text = "123 456 789";
    
    // 检查是否匹配
    assert!(re.is_match(text));

    // 查找第一个匹配
    if let Some(mat) = re.find(text) {
        println!("Found match: {}", mat.as_str()); // "123"
    }

    // 查找所有匹配
    for mat in re.find_iter(text) {
        println!("Match: {}", mat.as_str());
    }
}

1.3 编译时正则表达式

使用 lazy_static 优化性能:

rust 复制代码
use lazy_static::lazy_static;
use regex::Regex;

lazy_static! {
    static ref EMAIL_RE: Regex = Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").unwrap();
    static ref PHONE_RE: Regex = Regex::new(r"^1[3-9]\d{9}$").unwrap();
}

fn is_valid_email(email: &str) -> bool {
    EMAIL_RE.is_match(email)
}

fn is_valid_phone(phone: &str) -> bool {
    PHONE_RE.is_match(phone)
}

2. 正则表达式语法

2.1 字符匹配

rust 复制代码
use regex::Regex;

fn main() {
    let text = "Rust 2021 is awesome! Price: $99.99";

    // 匹配数字
    let digits = Regex::new(r"\d+").unwrap();
    for mat in digits.find_iter(text) {
        println!("Number: {}", mat.as_str());
    }

    // 匹配单词
    let words = Regex::new(r"\w+").unwrap();
    for mat in words.find_iter(text) {
        println!("Word: {}", mat.as_str());
    }

    // 匹配空白字符
    let spaces = Regex::new(r"\s+").unwrap();
    let parts: Vec<&str> = spaces.split(text).collect();
    println!("Parts: {:?}", parts);

    // 自定义字符类
    let vowels = Regex::new(r"[aeiou]").unwrap();
    for mat in vowels.find_iter(text) {
        println!("Vowel: {}", mat.as_str());
    }
}

2.2 捕获组

rust 复制代码
use regex::Regex;

fn main() {
    let text = "John Smith, Jane Doe, Bob Johnson";
    let re = Regex::new(r"(\w+)\s(\w+)").unwrap();

    // 使用命名捕获组
    let re_named = Regex::new(r"(?P<first>\w+)\s(?P<last>\w+)").unwrap();

    // 基本捕获
    for caps in re.captures_iter(text) {
        println!("Full name: {}", &caps[0]);
        println!("First name: {}", &caps[1]);
        println!("Last name: {}", &caps[2]);
    }

    // 命名捕获
    for caps in re_named.captures_iter(text) {
        println!(
            "First: {}, Last: {}",
            &caps["first"],
            &caps["last"]
        );
    }
}

3. 高级特性

3.1 替换操作

rust 复制代码
use regex::Regex;

fn main() {
    let text = "My phone is 123-456-7890";
    let re = Regex::new(r"\d{3}-\d{3}-\d{4}").unwrap();

    // 简单替换
    let result = re.replace(text, "XXX-XXX-XXXX");
    println!("{}", result);

    // 替换所有匹配
    let result = re.replace_all(text, "XXX-XXX-XXXX");
    println!("{}", result);

    // 使用回调函数替换
    let result = re.replace_all(text, |caps: &regex::Captures| {
        format!("PHONE({})", &caps[0])
    });
    println!("{}", result);
}

3.2 正则表达式集合

rust 复制代码
use regex::RegexSet;

fn main() {
    // 创建正则表达式集合
    let set = RegexSet::new(&[
        r"\w+@\w+\.\w+",    // 邮箱
        r"\d{3}-\d{3}-\d{4}", // 电话
        r"\d{5}",           // 邮编
    ]).unwrap();

    let text = "Contact: john@example.com, 123-456-7890, 12345";
    
    // 检查哪些模式匹配
    let matches: Vec<_> = set.matches(text).into_iter().collect();
    println!("Matching patterns: {:?}", matches);
}

4. 实用工具

4.1 验证器

rust 复制代码
use regex::Regex;
use lazy_static::lazy_static;

lazy_static! {
    static ref VALIDATORS: Validators = Validators::new();
}

pub struct Validators {
    email: Regex,
    phone: Regex,
    password: Regex,
    url: Regex,
}

impl Validators {
    fn new() -> Self {
        Self {
            email: Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").unwrap(),
            phone: Regex::new(r"^1[3-9]\d{9}$").unwrap(),
            password: Regex::new(r"^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$").unwrap(),
            url: Regex::new(r"^https?://[^\s/$.?#].[^\s]*$").unwrap(),
        }
    }

    pub fn is_valid_email(&self, email: &str) -> bool {
        self.email.is_match(email)
    }

    pub fn is_valid_phone(&self, phone: &str) -> bool {
        self.phone.is_match(phone)
    }

    pub fn is_valid_password(&self, password: &str) -> bool {
        self.password.is_match(password)
    }

    pub fn is_valid_url(&self, url: &str) -> bool {
        self.url.is_match(url)
    }
}

// 使用示例
fn validate_user_input(email: &str, phone: &str) -> Result<(), String> {
    if !VALIDATORS.is_valid_email(email) {
        return Err("Invalid email format".to_string());
    }
    if !VALIDATORS.is_valid_phone(phone) {
        return Err("Invalid phone format".to_string());
    }
    Ok(())
}

4.2 文本处理器

rust 复制代码
use regex::Regex;
use lazy_static::lazy_static;

lazy_static! {
    static ref TEXT_PROCESSOR: TextProcessor = TextProcessor::new();
}

pub struct TextProcessor {
    url: Regex,
    html_tag: Regex,
    whitespace: Regex,
}

impl TextProcessor {
    fn new() -> Self {
        Self {
            url: Regex::new(r"https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+[^\s]*").unwrap(),
            html_tag: Regex::new(r"<[^>]+>").unwrap(),
            whitespace: Regex::new(r"\s+").unwrap(),
        }
    }

    pub fn extract_urls(text: &str) -> Vec<String> {
        TEXT_PROCESSOR
            .url
            .find_iter(text)
            .map(|m| m.as_str().to_string())
            .collect()
    }

    pub fn strip_html_tags(html: &str) -> String {
        TEXT_PROCESSOR.html_tag.replace_all(html, "").to_string()
    }

    pub fn clean_whitespace(text: &str) -> String {
        TEXT_PROCESSOR
            .whitespace
            .replace_all(text.trim(), " ")
            .to_string()
    }
}

5. 性能优化

5.1 编译优化

rust 复制代码
use regex::RegexBuilder;

fn create_optimized_regex() -> regex::Regex {
    RegexBuilder::new(r"\b\w+\b")
        .case_insensitive(true)
        .multi_line(true)
        .dot_matches_new_line(true)
        .build()
        .unwrap()
}

5.2 性能考虑

rust 复制代码
use regex::Regex;
use lazy_static::lazy_static;

// 1. 使用 lazy_static 避免重复编译
lazy_static! {
    static ref PATTERN: Regex = Regex::new(r"\d+").unwrap();
}

// 2. 使用精确的模式
fn good_pattern() {
    let specific = Regex::new(r"^\d{3}$").unwrap();  // 更好
    let general = Regex::new(r"\d+").unwrap();       // 较差
}

// 3. 避免回溯
fn avoid_backtracking() {
    let bad = Regex::new(r".*foo.*").unwrap();       // 可能导致回溯
    let good = Regex::new(r"[^/]*foo[^/]*").unwrap(); // 更好的选择
}

// 4. 使用非捕获组
fn use_non_capturing_groups() {
    let capturing = Regex::new(r"(foo)").unwrap();     // 捕获组
    let non_capturing = Regex::new(r"(?:foo)").unwrap(); // 非捕获组
}

6. 错误处理

rust 复制代码
use regex::Regex;
use std::error::Error;

fn compile_regex(pattern: &str) -> Result<Regex, Box<dyn Error>> {
    match Regex::new(pattern) {
        Ok(re) => Ok(re),
        Err(e) => Err(Box::new(e)),
    }
}

fn safe_regex_match(pattern: &str, text: &str) -> Result<bool, Box<dyn Error>> {
    let re = compile_regex(pattern)?;
    Ok(re.is_match(text))
}

// 使用示例
fn main() -> Result<(), Box<dyn Error>> {
    match safe_regex_match(r"\d+", "123") {
        Ok(true) => println!("Pattern matched!"),
        Ok(false) => println!("Pattern did not match."),
        Err(e) => eprintln!("Error: {}", e),
    }
    Ok(())
}

7. 测试

rust 复制代码
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_email_validation() {
        assert!(VALIDATORS.is_valid_email("test@example.com"));
        assert!(!VALIDATORS.is_valid_email("invalid.email"));
        assert!(VALIDATORS.is_valid_email("user@domain.co.uk"));
    }

    #[test]
    fn test_phone_validation() {
        assert!(VALIDATORS.is_valid_phone("13812345678"));
        assert!(!VALIDATORS.is_valid_phone("12345678"));
        assert!(!VALIDATORS.is_valid_phone("23812345678"));
    }

    #[test]
    fn test_text_processing() {
        let html = "<p>Hello</p><div>World</div>";
        assert_eq!(
            TextProcessor::strip_html_tags(html),
            "HelloWorld"
        );

        let text = "  multiple   spaces   here  ";
        assert_eq!(
            TextProcessor::clean_whitespace(text),
            "multiple spaces here"
        );
    }
}

总结

Rust的正则表达式实现具有以下特点:

  1. 高性能的正则表达式引擎
  2. 安全的API设计
  3. 丰富的编译时优化选项
  4. 完整的Unicode支持

最佳实践:

  1. 使用 lazy_static 缓存编译后的正则表达式
  2. 选择合适的正则表达式构建方式
  3. 注意性能优化和内存使用
  4. 做好错误处理
  5. 编写完整的测试用例

注意事项:

  1. 正则表达式编译有开销,应该重用
  2. 使用适当的模式避免回溯
  3. 考虑使用 RegexSet 处理多个模式
  4. 注意字符串的生命周期

记住:在Rust中使用正则表达式时,要充分利用Rust的类型系统和所有权机制,确保代码既高效又安全。合理使用 lazy_static 和其他优化技术可以显著提高性能。

相关推荐
wlyang66610 分钟前
4. scala高阶之隐式转换与泛型
大数据·开发语言·后端·spark·scala
JovaZou2 小时前
[Python学习日记-75] 计算机基础与网络
开发语言·网络·python·网络协议·学习·tcp/ip·计算机网络
五行星辰4 小时前
Servlet与JSP:Java的秘密花园入口
java·开发语言·servlet
代码驿站5204 小时前
Scala语言的软件工程
开发语言·后端·golang
Code花园4 小时前
Objective-C语言的多线程编程
开发语言·后端·golang
Rverdoser5 小时前
接口项目架构流程图-thinkphp6-rabbitmq
开发语言·microsoft·ruby
Jelena技术达人5 小时前
利用 Python 爬虫获取 1688 关键字 API 接口
开发语言·爬虫·python
graceyun5 小时前
C语言初阶习题【23】输出数组的前5项之和
c语言·开发语言·算法
喵手6 小时前
Java中将特征向量转换为矩阵的实现
java·开发语言·矩阵
晚安~~6 小时前
协同过滤算法商品推荐系统|Java|SpringBoot|VUE|
java·开发语言·maven