共计 3363 个字符,预计需要花费 9 分钟才能阅读完成。
新人学习 rust ffi,实在搞不定,特来请教一下
下面段代码主要是实现一个简单的字符串然后通过 FFI 调用 hyperscan(这是一个 C++ 写的库,我通过 lib 调用,完全静态编译)的正则表达式同时匹配多个 pattern,然后打印每一个 pattern 出现的第一个位置即可,如果没出现打印 -1。
但是这个代码我怎么改都是 -1 或者 0,就是不能有正确结果,我问了多个 AI,但是都始终无法解决这个问题,所以想向大神请教一下,非常感谢。
运行结果如下:
Hyperscan 版本: 5.4.2 2024-10-06
模式 "test" 未出现,位置: -1
模式 "string" 未出现,位置: -1
模式 "example" 未出现,位置: -1
模式 "中文" 未出现,位置: -1
完整代码如下:
use std::ffi::{CStr, CString};
use std::os::raw::{c_int, c_uint, c_void};
use std::ptr;
const HS_MODE_BLOCK: c_uint = 1;
const HS_FLAG_LITERAL: c_uint = 1 << 10; // 添加 HS_FLAG_LITERAL 常量
#[link(name = "hs")]
extern "C" {fn hs_version() -> *const i8;
pub fn hs_compile_multi(
expressions: *const *const i8,
flags: *const c_uint,
ids: *const c_uint,
elements: c_uint,
mode: c_uint,
platform: *const c_void,
db: *mut *mut hs_database_t,
compile_err: *mut *mut hs_compile_error_t,
) -> c_int;
pub fn hs_alloc_scratch(
db: *const hs_database_t,
scratch: *mut *mut hs_scratch_t,
) -> c_int;
pub fn hs_free_scratch(scratch: *mut hs_scratch_t,) -> c_int;
pub fn hs_scan(
db: *const hs_database_t,
data: *const i8,
length: c_uint,
flags: c_uint,
scratch: *mut hs_scratch_t,
match_event_handler: Option<
extern "C" fn(
id: c_uint,
from: u64,
to: u64,
flags: c_uint,
context: *mut c_void,
) -> c_int,
>,
context: *mut c_void,
) -> c_int;
pub fn hs_free_database(db: *mut hs_database_t) -> c_int;
pub fn hs_free_compile_error(error: *mut hs_compile_error_t);
}
pub enum hs_database_t {}
pub enum hs_scratch_t {}
#[repr(C)]
pub struct hs_compile_error_t {
pub message: *const i8,
pub expression: c_int,
}
const HS_SUCCESS: c_int = 0;
extern "C" fn event_handler(
id: c_uint,
from: u64,
_to: u64,
_flags: c_uint,
context: *mut c_void,
) -> c_int {
unsafe {
let positions = context as *mut u64;
let pos_ptr = positions.add(id as usize);
if *pos_ptr == u64::MAX {*pos_ptr = from;}
}
0
}
fn main() {
unsafe {
// 获取并打印 Hyperscan 版本
let version = hs_version();
let c_str = CStr::from_ptr(version);
let str_slice = c_str.to_str().unwrap();
println!("Hyperscan 版本: {}", str_slice);
// 定义要匹配的模式列表
let patterns = vec!["test", "string", "example", "中文"];
// 将模式转换为 CString
let c_patterns: Vec = patterns
.iter()
.map(|s| CString::new(*s).unwrap())
.collect();
// 创建 expressions、flags、ids 数组
let expressions: Vec<*const i8> = c_patterns.iter().map(|s| s.as_ptr()).collect();
// 使用 HS_FLAG_LITERAL 标志
let flags: Vec = vec![HS_FLAG_LITERAL; patterns.len()];
let ids: Vec = (0..patterns.len() as c_uint).collect();
// 编译模式
let mut db: *mut hs_database_t = ptr::null_mut();
let mut compile_err: *mut hs_compile_error_t = ptr::null_mut();
let compile_result = hs_compile_multi(expressions.as_ptr(),
flags.as_ptr(),
ids.as_ptr(),
patterns.len() as c_uint,
HS_MODE_BLOCK,
ptr::null(),
&mut db,
&mut compile_err,
);
if compile_result != HS_SUCCESS {if !compile_err.is_null() {
let err = &*compile_err;
let message = CStr::from_ptr(err.message).to_string_lossy();
println!("编译错误: {}", message);
hs_free_compile_error(compile_err);
} else {println!("未知的编译错误");
}
return;
}
// 分配 scratch 空间
let mut scratch: *mut hs_scratch_t = ptr::null_mut();
let alloc_result = hs_alloc_scratch(db, &mut scratch);
if alloc_result != HS_SUCCESS {println!("hs_alloc_scratch 失败");
hs_free_database(db);
return;
}
// 定义输入字符串
let input = "This is a test string for example purposes 中文测试.";
// 初始化匹配位置数组
let mut match_positions: Vec = vec![u64::MAX; patterns.len()];
// 执行扫描
let scan_result = hs_scan(
db,
input.as_ptr() as *const i8,
input.len() as c_uint,
0,
scratch,
Some(event_handler),
match_positions.as_mut_ptr() as *mut c_void,);
if scan_result != HS_SUCCESS {println!("hs_scan 失败,错误代码: {}", scan_result);
hs_free_scratch(scratch);
hs_free_database(db);
return;
}
// 输出结果
for (i, pattern) in patterns.iter().enumerate() {let pos = match_positions[i];
if pos != u64::MAX {println!("模式"{}"首次出现位置: {}", pattern, pos);
} else {println!("模式"{}"未出现,位置: -1", pattern);
}
}
// 释放资源
hs_free_scratch(scratch);
hs_free_database(db);
}
}
正文完