Rust正则表达式库pcre2的使用,高性能PCRE2绑定实现复杂文本匹配与模式搜索

Rust正则表达式库pcre2的使用,高性能PCRE2绑定实现复杂文本匹配与模式搜索

pcre2是一个高级的Rust封装库,用于PCRE2(Perl兼容正则表达式2)库。

安装

在项目目录中运行以下Cargo命令:

cargo add pcre2

或者在Cargo.toml中添加:

pcre2 = "0.2.9"

使用示例

以下是一个完整的Rust示例,展示如何使用pcre2库进行正则表达式匹配:

use pcre2::bytes::Regex;

fn main() {
    // 编译正则表达式
    let re = Regex::new(r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})").unwrap();
    
    // 要匹配的文本
    let text = b"Today is 2023-04-15, tomorrow is 2023-04-16";
    
    // 查找所有匹配项
    for result in re.captures_iter(text) {
        let caps = result.unwrap();
        
        // 获取命名捕获组
        println!("Year: {}", String::from_utf8_lossy(caps.name("year").unwrap().as_bytes()));
        println!("Month: {}", String::from_utf8_lossy(caps.name("month").unwrap().as_bytes()));
        println!("Day: {}", String::from_utf8_lossy(caps.name("day").unwrap().as_bytes()));
        println!("---");
    }
    
    // 替换文本
    let replaced = re.replace_all(text, b"$month/$day/$year");
    println!("Replaced: {}", String::from_utf8_lossy(&replaced));
}

高级功能示例

use pcre2::bytes::{Regex, RegexBuilder};

fn main() {
    // 使用构建器配置正则表达式
    let re = RegexBuilder::new()
        .caseless(true)  // 不区分大小写
        .dotall(true)    // .匹配所有字符包括换行符
        .build(r"^hello.*world$")
        .unwrap();
    
    let text = b"HELLO\nRust\nWORLD";
    
    if re.is_match(text).unwrap() {
        println!("Pattern matched!");
    }
    
    // 使用JIT编译加速匹配
    let re = RegexBuilder::new()
        .jit(true)
        .build(r"\b\w{5}\b")  // 匹配5字母单词
        .unwrap();
    
    let text = b"The quick brown fox jumps over the lazy dog";
    let count = re.find_iter(text).count();
    println!("Found {} five-letter words", count);
}

完整示例demo

以下是一个结合基本使用和高级功能的完整示例:

use pcre2::bytes::{Regex, RegexBuilder};

fn main() {
    // 示例1:基本日期匹配和替换
    println!("=== 基本日期匹配示例 ===");
    let date_re = Regex::new(r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})").unwrap();
    let text = b"Dates: 2023-04-15, 2023-04-16, 2023-04-17";
    
    for cap in date_re.captures_iter(text) {
        let caps = cap.unwrap();
        println!("完整匹配: {}", String::from_utf8_lossy(caps.get(0).unwrap().as_bytes()));
        println!("年-月-日: {}-{}-{}", 
            String::from_utf8_lossy(caps.name("year").unwrap().as_bytes()),
            String::from_utf8_lossy(caps.name("month").unwrap().as_bytes()),
            String::from_utf8_lossy(caps.name("day").unwrap().as_bytes()));
    }
    
    let replaced = date_re.replace_all(text, b"$day/$month/$year");
    println!("替换后文本: {}", String::from_utf8_lossy(&replaced));
    
    // 示例2:高级匹配选项
    println!("\n=== 高级匹配选项示例 ===");
    let advanced_re = RegexBuilder::new()
        .caseless(true)
        .multi_line(true)
        .build(r"^hello.*world$")
        .unwrap();
    
    let multiline_text = b"HELLO\nThis is a test\nWORLD";
    if advanced_re.is_match(multiline_text).unwrap() {
        println!("多行匹配成功!");
    }
    
    // 示例3:JIT加速匹配
    println!("\n=== JIT加速匹配示例 ===");
    let jit_re = RegexBuilder::new()
        .jit(true)
        .build(r"\b[a-zA-Z]{5}\b")  // 匹配5字母单词
        .unwrap();
    
    let sample_text = b"The quick brown fox jumps over the lazy dog";
    let matches: Vec<_> = jit_re.find_iter(sample_text).collect();
    println!("找到 {} 个5字母单词:", matches.len());
    for m in matches {
        println!("- {}", String::from_utf8_lossy(&sample_text[m.unwrap().range()]));
    }
}

注意事项

目前这个库是PCRE2的一个相对轻量级的封装层,还没有完全覆盖PCRE2的所有功能。没有具体的计划来进一步扩展这个封装,但欢迎提交PR来使更多的PCRE2功能可用。

许可证

双重许可:MIT或UNLICENSE


1 回复

Rust正则表达式库pcre2的使用指南

概述

pcre2是Rust中一个高性能的PCRE2绑定库,提供了Perl兼容正则表达式的强大功能。相比Rust标准库中的regexpcre2支持更多高级特性,如回溯引用、条件子模式等,适合需要复杂模式匹配的场景。

安装

Cargo.toml中添加依赖:

[dependencies]
pcre2 = "0.2"

基本用法

简单匹配

use pcre2::bytes::Regex;

fn main() {
    // 创建匹配日期格式的正则表达式
    let re = Regex::new(r"\d{4}-\d{2}-\d{2}").unwrap();
    let text = "Today is 2023-04-15";
    
    // 检查文本中是否包含匹配项
    if re.is_match(text.as_bytes()).unwrap() {
        println!("Found a date!");
    }
}

提取匹配项

use pcre2::bytes::Regex;

fn main() {
    // 创建带捕获组的正则表达式
    let re = Regex::new(r"(\d{4})-(\d{2})-(\d{2})").unwrap();
    let text = "Dates: 2023-04-15, 2022-12-31";
    
    // 遍历所有匹配项
    let matches = re.captures_iter(text.as_bytes());
    
    for mat in matches {
        let mat = mat.unwrap();
        println!("Full match: {}", String::from_utf8_lossy(mat.get(0).unwrap()));
        println!("Year: {}", String::from_utf8_lossy(mat.get(1).unwrap()));
        println!("Month: {}", String::from_utf8_lossy(mat.get(2).unwrap()));
        println!("Day: {}", String::from_utf8_lossy(mat.get(3).unwrap()));
    }
}

高级特性

命名捕获组

use pcre2::bytes::Regex;

fn main() {
    // 使用命名捕获组的正则表达式
    let re = Regex::new(r"(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})").unwrap();
    let text = "Date: 2023-04-15";
    
    // 获取命名捕获组
    let caps = re.captures(text.as_bytes()).unwrap().unwrap();
    
    println!("Year: {}", String::from_utf8_lossy(caps.name("year").unwrap()));
    println!("Month: {}", String::from_utf8_lossy(caps.name("month").unwrap()));
    println!("Day: {}", String::from_utf8_lossy(caps.name("day").unwrap()));
}

替换文本

use pcre2::bytes::Regex;

fn main() {
    // 创建匹配日期格式的正则表达式
    let re = Regex::new(r"(\d{2})/(\d{2})/(\d{4})").unwrap();
    let text = "Date: 04/15/2023";
    
    // 替换日期格式
    let result = re.replace(text.as_bytes(), &b"$3-$1-$2"[..]).unwrap();
    
    println!("{}", String::from_utf8_lossy(&result));
    // 输出: Date: 2023-04-15
}

性能优化

对于需要重复使用的正则表达式,可以编译后复用:

use pcre2::bytes::Regex;

// 使用lazy_static全局缓存正则表达式
lazy_static::lazy_static! {
    static ref DATE_RE: Regex = Regex::new(r"\d{4}-\d{2}-\d{2}").unwrap();
}

fn main() {
    let text = "Today is 2023-04-15";
    if DATE_RE.is_match(text.as_bytes()).unwrap() {
        println!("Found a date!");
    }
}

完整示例

下面是一个综合使用pcre2各种功能的完整示例:

use pcre2::bytes::Regex;
use lazy_static::lazy_static;

// 预编译正则表达式
lazy_static! {
    // 匹配电子邮件地址
    static ref EMAIL_RE: Regex = Regex::new(
        r"(?x)
        ^[a-zA-Z0-9._%+-]+      # 用户名
        @                        # @符号
        [a-zA-Z0-9.-]+           # 域名
        \.[a-zA-Z]{2,}$          # 顶级域名
        "
    ).unwrap();
    
    // 匹配并提取URL各部分
    static ref URL_RE: Regex = Regex::new(
        r"(?x)
        ^
        (?<scheme>https?|ftp)://  # 协议
        (?<host>[^/\s]+)          # 主机名
        (?:/(?<path>[^\s]*))?     # 路径(可选)
        $"
    ).unwrap();
}

fn main() {
    // 1. 简单匹配示例
    let date_re = Regex::new(r"\d{4}-\d{2}-\d{2}").unwrap();
    let text = "Event date: 2023-12-25";
    println!("Contains date: {}", date_re.is_match(text.as_bytes()).unwrap());
    
    // 2. 提取匹配项示例
    let phone_re = Regex::new(r"(\d{3})-(\d{3})-(\d{4})").unwrap();
    let contact = "Phone: 123-456-7890, Fax: 987-654-3210";
    
    for cap in phone_re.captures_iter(contact.as_bytes()) {
        let cap = cap.unwrap();
        println!("Phone: {}-{}-{}", 
            String::from_utf8_lossy(cap.get(1).unwrap()),
            String::from_utf8_lossy(cap.get(2).unwrap()),
            String::from_utf8_lossy(cap.get(3).unwrap()));
    }
    
    // 3. 命名捕获组示例
    let log_re = Regex::new(
        r"\[(?<time>\d{2}:\d{2}:\d{2})\] \[(?<level>\w+)\] (?<message>.+)"
    ).unwrap();
    
    let log_entry = "[14:30:22] [ERROR] Connection timeout";
    if let Some(caps) = log_re.captures(log_entry.as_bytes()).unwrap() {
        println!(
            "Log - Time: {}, Level: {}, Message: {}",
            String::from_utf8_lossy(caps.name("time").unwrap()),
            String::from_utf8_lossy(caps.name("level").unwrap()),
            String::from_utf8_lossy(caps.name("message").unwrap())
        );
    }
    
    // 4. 替换文本示例
    let reorder_re = Regex::new(r"(\w+), (\w+)").unwrap();
    let names = "Smith, John\nDoe, Jane";
    let result = reorder_re.replace_all(names.as_bytes(), &b"$2 $1"[..]).unwrap();
    println!("Reordered names:\n{}", String::from_utf8_lossy(&result));
    
    // 5. 使用预编译的正则表达式
    println!("Is 'test@example.com' valid: {}", 
        EMAIL_RE.is_match(b"test@example.com").unwrap());
        
    if let Some(caps) = URL_RE.captures(b"https://www.example.com/path/to/page").unwrap() {
        println!(
            "URL - Scheme: {}, Host: {}, Path: {}",
            String::from_utf8_lossy(caps.name("scheme").unwrap()),
            String::from_utf8_lossy(caps.name("host").unwrap()),
            String::from_utf8_lossy(caps.name("path").unwrap_or_default())
        );
    }
}

注意事项

  1. PCRE2支持比Rust标准库regex更多的特性,但也可能带来更大的二进制体积
  2. 复杂正则表达式可能导致性能下降,特别是使用回溯引用时
  3. 默认情况下,pcre2使用UTF-8检查,可以通过Builder禁用以提高性能
回到顶部