新人学习 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<CString> = 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<c_uint> = vec![HS_FLAG_LITERAL; patterns.len()];
let ids: Vec<c_uint> = (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<u64> = 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);
}
}
1
PTLin 59 天前
调用 cpp 的库用 https://cxx.rs/ ,cpp 的 api 和 c 不一样,用 extern "C"未必好使。
|
2
gwy15 59 天前
const HS_FLAG_LITERAL: c_uint = 1 << 10; // 添加 HS_FLAG_LITERAL 常量
这一行的问题,换成其他的可以正常匹配 |
3
gwy15 59 天前
* Compile flag: Don't do any match reporting.
* * This flag instructs Hyperscan to ignore match reporting for this expression. * It is designed to be used on the sub-expressions in logical combinations. */ #define HS_FLAG_QUIET 1024 你给的 flag 会导致 onEvent 不被调用,自然也就不会写入结果 |