Rust正则表达式库pcre2-sys的使用:高性能PCRE2绑定与UTF-8模式支持
Rust正则表达式库pcre2-sys的使用:高性能PCRE2绑定与UTF-8模式支持
概述
pcre2-sys是Rust语言对PCRE2(Perl Compatible Regular Expressions 2)库的绑定。PCRE2是一个强大的正则表达式库,提供与Perl兼容的正则表达式功能。
特性
- 提供PCRE2库的原始绑定
- 支持PCRE2 10.42版本
- 默认优先动态链接系统PCRE2库
- 支持静态链接(通过环境变量控制)
- 目前仅支持
libpcre-8
(PCRE2_CODE_UNIT_WIDTH=8)
安装
在项目目录中运行以下Cargo命令:
cargo add pcre2-sys
或者在Cargo.toml中添加:
pcre2-sys = "0.2.9"
构建选项
PCRE2_SYS_STATIC=1
:强制静态链接PCRE2_SYS_STATIC=0
:强制禁用静态链接PCRE2_SYS_DEBUG
:在静态构建时强制启用调试符号
使用示例
以下是使用pcre2-sys进行正则表达式匹配的基本示例:
use pcre2_sys::*;
fn main() {
// 初始化PCRE2编译上下文
let compile_context = unsafe { pcre2_compile_context_create_8(std::ptr::null_mut()) };
// 定义正则表达式模式
let pattern = b"Hello, (\\w+)!";
let pattern_len = pattern.len() as size_t;
// 定义错误缓冲区和偏移量
let mut error_buffer = [0i8; 256];
let mut error_offset = 0;
// 编译正则表达式
let re = unsafe {
pcre2_compile_8(
pattern.as_ptr(),
pattern_len,
0,
&mut error_buffer.as_mut_ptr(),
&mut error_offset,
compile_context,
)
};
// 检查编译是否成功
if re.is_null() {
let error_msg = unsafe { std::ffi::CStr::from_ptr(error_buffer.as_ptr()) };
eprintln!("PCRE2 compilation failed at offset {}: {}", error_offset, error_msg.to_string_lossy());
return;
}
// 创建匹配上下文
let match_context = unsafe { pcre2_match_context_create_8(std::ptr::null_mut()) };
// 准备要匹配的字符串
let subject = b"Hello, Rust!";
let subject_len = subject.len() as size_t;
// 准备匹配数据缓冲区
let mut ovector = [0; 30]; // 足够大的向量来存储匹配结果
let rc = unsafe {
pcre2_match_8(
re,
subject.as_ptr(),
subject_len,
0, // 起始偏移量
0, // 选项
ovector.as_mut_ptr(),
ovector.len() as size_t,
match_context,
)
};
// 检查匹配结果
if rc > 0 {
println!("Match succeeded!");
// 提取捕获组
let start = ovector[2] as usize;
let end = ovector[3] as usize;
let matched = &subject[start..end];
println!("Captured group: {}", String::from_utf8_lossy(matched));
} else if rc == PCRE2_ERROR_NOMATCH {
println!("No match found");
} else {
println!("Matching error occurred");
}
// 清理资源
unsafe {
pcre2_code_free_8(re);
pcre2_compile_context_free_8(compile_context);
pcre2_match_context_free_8(match_context);
}
}
UTF-8支持示例
以下示例展示如何使用pcre2-sys处理UTF-8编码的字符串:
use pcre2_sys::*;
fn utf8_regex_match() {
// 编译支持UTF-8的正则表达式
let pattern = "こんにちは、(\\p{L}+)!".as_bytes();
let pattern_len = pattern.len() as size_t;
let mut error_buffer = [0i8; 256];
let mut error_offset = 0;
let re = unsafe {
pcre2_compile_8(
pattern.as_ptr(),
pattern_len,
PCRE2_UTF, // 启用UTF-8支持
&mut error_buffer.as_mut_ptr(),
&mut error_offset,
std::ptr::null_mut(),
)
};
if re.is_null() {
let error_msg = unsafe { std::ffi::CStr::from_ptr(error_buffer.as_ptr()) };
eprintln!("Compilation failed: {}", error_msg.to_string_lossy());
return;
}
// 准备UTF-8字符串
let subject = "こんにちは、Rust!".as_bytes();
let subject_len = subject.len() as size_t;
let mut ovector = [0; 30];
let rc = unsafe {
pcre2_match_8(
re,
subject.as_ptr(),
subject_len,
0,
0,
ovector.as_mut_ptr(),
ovector.len() as size_t,
std::ptr::null_mut(),
)
};
if rc > 0 {
let start = ovector[2] as usize;
let end = ovector[3] as usize;
let matched = &subject[start..end];
println!("Matched UTF-8 text: {}", String::from_utf8_lossy(matched));
}
unsafe {
pcre2_code_free_8(re);
}
}
完整示例代码
以下是一个结合基本匹配和UTF-8支持的完整示例:
use pcre2_sys::*;
fn main() {
// 示例1:基本正则匹配
basic_regex_match();
// 示例2:UTF-8正则匹配
utf8_regex_match();
}
fn basic_regex_match() {
println!("=== 基本正则匹配示例 ===");
// 初始化编译上下文
let compile_context = unsafe { pcre2_compile_context_create_8(std::ptr::null_mut()) };
// 编译正则表达式
let pattern = b"Hello, (\\w+)!";
let re = compile_regex(pattern, 0, compile_context);
// 执行匹配
let subject = b"Hello, Rust!";
match_regex(re, subject);
// 清理资源
unsafe {
pcre2_compile_context_free_8(compile_context);
}
}
fn utf8_regex_match() {
println!("\n=== UTF-8正则匹配示例 ===");
// 编译支持UTF-8的正则表达式
let pattern = "こんにちは、(\\p{L}+)!".as_bytes();
let re = compile_regex(pattern, PCRE2_UTF, std::ptr::null_mut());
// 执行匹配
let subject = "こんにちは、Rust!".as_bytes();
match_regex(re, subject);
}
// 编译正则表达式的辅助函数
fn compile_regex(pattern: &[u8], options: u32, context: *mut pcre2_compile_context_8) -> *mut pcre2_code_8 {
let pattern_len = pattern.len() as size_t;
let mut error_buffer = [0i8; 256];
let mut error_offset = 0;
let re = unsafe {
pcre2_compile_8(
pattern.as_ptr(),
pattern_len,
options,
&mut error_buffer.as_mut_ptr(),
&mut error_offset,
context,
)
};
if re.is_null() {
let error_msg = unsafe { std::ffi::CStr::from_ptr(error_buffer.as_ptr()) };
eprintln!("正则表达式编译失败: {}", error_msg.to_string_lossy());
std::process::exit(1);
}
re
}
// 执行正则匹配的辅助函数
fn match_regex(re: *mut pcre2_code_8, subject: &[u8]) {
let subject_len = subject.len() as size_t;
let mut ovector = [0; 30];
let rc = unsafe {
pcre2_match_8(
re,
subject.as_ptr(),
subject_len,
0,
0,
ovector.as_mut_ptr(),
ovector.len() as size_t,
std::ptr::null_mut(),
)
};
match rc {
n if n > 0 => {
println!("匹配成功!");
let start = ovector[2] as usize;
let end = ovector[3] as usize;
let matched = &subject[start..end];
println!("捕获组: {}", String::from_utf8_lossy(matched));
},
PCRE2_ERROR_NOMATCH => println!("未找到匹配"),
_ => println!("匹配过程中发生错误"),
}
unsafe {
pcre2_code_free_8(re);
}
}
注意事项
- 这是一个
-sys
绑定库,主要提供PCRE2的原始绑定 - 使用前应查阅PCRE2官方文档了解详细API
- 在Windows上使用GNU工具链时需要安装兼容的C编译器(如MinGW-w64)
- 已测试支持Windows、Linux和macOS平台
许可证
双重许可:MIT或UNLICENSE
1 回复
Rust正则表达式库pcre2-sys的使用:高性能PCRE2绑定与UTF-8模式支持
pcre2-sys
是 Rust 语言对 PCRE2 (Perl Compatible Regular Expressions 2) 库的原始系统绑定,提供了高性能的正则表达式处理能力,特别支持 UTF-8 编码模式。
主要特性
- 完整的 PCRE2 功能绑定
- 支持 UTF-8 编码模式
- 高性能正则表达式匹配
- 支持 JIT 编译加速
- 提供 Unicode 属性支持
使用方法
添加依赖
首先在 Cargo.toml
中添加依赖:
[dependencies]
pcre2-sys = "0.2"
基本使用示例
use pcre2_sys::*;
fn main() {
unsafe {
// 创建编译上下文
let mut compile_context: *mut pcre2_compile_context_8 = std::ptr::null_mut();
compile_context = pcre2_compile_context_create_8(std::ptr::null_mut());
// 正则表达式模式
let pattern = b"hello\\s+world\x00" as *const u8;
// 错误代码和偏移量
let mut errorcode = 0;
let mut erroroffset = 0;
// 编译正则表达式
let re = pcre2_compile_8(
pattern,
PCRE2_ZERO_TERMINATED,
0,
&mut errorcode,
&mut erroroffset,
compile_context,
);
if re.is_null() {
println!("正则表达式编译失败");
return;
}
// 创建匹配上下文
let match_context = pcre2_match_context_create_8(std::ptr::null_mut());
// 准备匹配字符串
let subject = b"hello world\x00" as *const u8;
let subject_length = 13;
// 执行匹配
let rc = pcre2_match_8(
re,
subject,
subject_length,
0,
0,
match_context,
std::ptr::null_mut(),
);
if rc >= 0 {
println!("匹配成功!");
} else {
println!("匹配失败");
}
// 释放资源
pcre2_code_free_8(re);
pcre2_compile_context_free_8(compile_context);
pcre2_match_context_free_8(match_context);
}
}
UTF-8 模式使用
use pcre2_sys::*;
fn utf8_example() {
unsafe {
let pattern = b"\\p{L}+\x00" as *const u8; // 匹配任何字母字符
let mut errorcode = 0;
let mut erroroffset = 0;
let re = pcre2_compile_8(
pattern,
PCRE2_ZERO_TERMINATED,
PCRE2_UCP | PCRE2_UTF, // 启用Unicode属性和UTF-8模式
&mut errorcode,
&mut erroroffset,
std::ptr::null_mut(),
);
if re.is_null() {
println!("编译失败");
return;
}
let subject = "こんにちは世界\x00".as_ptr() as *const u8;
let rc = pcre2_match_8(
re,
subject,
PCRE2_ZERO_TERMINATED,
0,
0,
std::ptr::null_mut(),
std::ptr::null_mut(),
);
if rc >= 0 {
println!("匹配到UTF-8文本!");
}
pcre2_code_free_8(re);
}
}
高级功能
JIT 编译加速
unsafe {
// ... 编译正则表达式后
let jit_ret = pcre2_jit_compile_8(re, PCRE2_JIT_COMPLETE as u32);
if jit_ret == 0 {
println!("JIT编译成功");
}
// 使用JIT进行匹配
let rc = pcre2_jit_match_8(
re,
subject,
subject_length,
0,
0,
match_context,
std::ptr::null_mut(),
);
// ...
}
捕获组提取
unsafe {
// ... 匹配成功后
let mut ovector = [0; 30]; // 足够大的空间存储匹配结果
let rc = pcre2_match_8(
re,
subject,
subject_length,
0,
0,
match_context,
ovector.as_mut_ptr(),
);
if rc > 0 {
for i in 0..rc {
let start = ovector[2*i];
let end = ovector[2*i+1];
let slice = std::slice::from_raw_parts(subject.add(start), end - start);
println!("捕获组 {}: {:?}", i, slice);
}
}
}
注意事项
pcre2-sys
是底层绑定,使用时需要大量 unsafe 代码- 对于大多数应用,可以考虑使用更高层次的封装如
pcre2
crate - 需要确保 PCRE2 库已正确安装在系统中
- 处理错误时需要检查返回值和错误代码
性能建议
- 对于重复使用的正则表达式,应缓存编译后的模式
- 启用 JIT 编译可以显著提高匹配性能
- 对于简单模式,考虑使用 Rust 标准库的
regex
crate 可能更高效
完整示例代码
下面是一个结合了基本使用、UTF-8模式和JIT编译的完整示例:
use pcre2_sys::*;
fn main() {
// 示例1: 基本使用
basic_example();
// 示例2: UTF-8模式
utf8_example();
// 示例3: JIT编译
jit_example();
}
fn basic_example() {
unsafe {
println!("=== 基本使用示例 ===");
// 初始化编译上下文
let compile_context = pcre2_compile_context_create_8(std::ptr::null_mut());
// 编译正则表达式
let pattern = b"\\d{3}-\\d{4}\x00" as *const u8; // 匹配电话号码格式
let mut errorcode = 0;
let mut erroroffset = 0;
let re = pcre2_compile_8(
pattern,
PCRE2_ZERO_TERMINATED,
0,
&mut errorcode,
&mut erroroffset,
compile_context,
);
if re.is_null() {
println!("正则表达式编译失败,错误码: {}", errorcode);
pcre2_compile_context_free_8(compile_context);
return;
}
// 匹配测试
let subject = b"电话: 123-4567\x00" as *const u8;
let rc = pcre2_match_8(
re,
subject,
PCRE2_ZERO_TERMINATED,
0,
0,
std::ptr::null_mut(),
std::ptr::null_mut(),
);
if rc >= 0 {
println!("找到匹配的电话号码!");
} else {
println!("未找到匹配");
}
// 清理资源
pcre2_code_free_8(re);
pcre2_compile_context_free_8(compile_context);
}
}
fn utf8_example() {
unsafe {
println!("\n=== UTF-8模式示例 ===");
// 编译支持UTF-8和Unicode属性的正则表达式
let pattern = b"\\p{Script=Han}+\x00" as *const u8; // 匹配中文字符
let mut errorcode = 0;
let mut erroroffset = 0;
let re = pcre2_compile_8(
pattern,
PCRE2_ZERO_TERMINATED,
PCRE2_UCP | PCRE2_UTF,
&mut errorcode,
&mut erroroffset,
std::ptr::null_mut(),
);
if re.is_null() {
println!("UTF-8正则表达式编译失败");
return;
}
// 测试UTF-8字符串
let subject = "这是中文文本\x00".as_ptr() as *const u8;
let rc = pcre2_match_8(
re,
subject,
PCRE2_ZERO_TERMINATED,
0,
0,
std::ptr::null_mut(),
std::ptr::null_mut(),
);
if rc >= 0 {
println!("成功匹配中文字符!");
}
pcre2_code_free_8(re);
}
}
fn jit_example() {
unsafe {
println!("\n=== JIT编译示例 ===");
// 编译正则表达式
let pattern = b"(\\d{4})-(\\d{2})-(\\d{2})\x00" as *const u8; // 匹配日期格式
let mut errorcode = 0;
let mut erroroffset = 0;
let re = pcre2_compile_8(
pattern,
PCRE2_ZERO_TERMINATED,
0,
&mut errorcode,
&mut erroroffset,
std::ptr::null_mut(),
);
if re.is_null() {
println!("正则表达式编译失败");
return;
}
// JIT编译
let jit_ret = pcre2_jit_compile_8(re, PCRE2_JIT_COMPLETE as u32);
if jit_ret != 0 {
println!("JIT编译失败");
pcre2_code_free_8(re);
return;
}
// 准备匹配数据
let subject = b"日期: 2023-04-15\x00" as *const u8;
let mut ovector = [0; 30];
// 使用JIT进行匹配
let rc = pcre2_jit_match_8(
re,
subject,
PCRE2_ZERO_TERMINATED,
0,
0,
std::ptr::null_mut(),
ovector.as_mut_ptr(),
);
if rc > 0 {
println!("匹配成功,找到 {} 个捕获组", rc - 1);
// 提取捕获组
for i in 0..rc {
let start = ovector[2*i];
let end = ovector[2*i+1];
let slice = std::slice::from_raw_parts(subject.add(start), end - start);
println!("组 {}: {:?}", i, std::str::from_utf8(slice).unwrap());
}
}
pcre2_code_free_8(re);
}
}
这个完整示例展示了:
- 基本正则表达式匹配
- UTF-8和Unicode属性支持
- JIT编译加速
- 捕获组提取
- 资源管理和错误处理
使用时需要注意所有PCRE2函数调用都在unsafe块中,并且需要手动管理内存。