共计 4248 个字符,预计需要花费 11 分钟才能阅读完成。
hyperscan 作为和 intel 深度绑定的政策匹配工具,提供了及其弱小的正则匹配性能,并提供接口,不便对匹配后果进行二次操作。
我在学习 hyperscan 时,在各大论坛并没有找到比拟齐备并且具体解说,很多只是提到了函数库大略时干什么的,索性将本人理解到的货色,具体的记录下来,也算是本人对 hyperscan 的一次坚固
hyperscan 是英特尔开源的一款正则匹配工具,与 intel 芯片深度绑定,intel 对其有专门的优化,因而在整体的匹配效率上,相较于其余正则计划,处于一个较为当先的地位。hyperscan 反对 pcre 正则规定,现有的次要利用计划大都是基于 pcre 做的匹配。
样例代码放在了 github 上,前面会贴出来。
注:本文演示环境为 ubuntu 22.04
hyperscan 下载安装
- 下载
intel 在 github 上凋谢了源码,通过 git 即可下载,因为 github,在国内拜访不敌对,在 gitee 上也有相干开源代码
github
git clone https://github.com/intel/hyperscan.git
gitee
git clone https://gitee.com/tzichengchew/hyperscan.git
- 依赖
hyperscan 应用 cmake 编译 cmake 等根底库装置不再赘述,须要依赖 - boost
Boost Downloads
- ragel
Ragel State Machine Compiler (colm.net)
git clone https://github.com/adrian-thurston/ragel.git
* colm
git clone https://github.com/adrian-thurston/colm.git
其中 ragel 的装置须要 clom 反对在官网均能找到下载地址。或者 git 地址
- 装置
装置 boost
bash bootstrap.sh && ./b2 && ./b2 install
装置 ragel
不倡议编译装置,坑很多
sudo apt install ragel
编译装置 hyperscan
创立一个目录
mkdir hyperscan_comp
执行编译命令
cmake $HYPERSCAN_PATH
make && make install
须要蛮久的。
遇到一个十分辣手的问题:
undefined reference to `avx2_memset'undefined reference to `corei7_memset'
…………
https://github.com/intel/hyperscan/issues/292#issuecomment-762635447
亲测无效。
我在另外一台设施上测试发现并没有报错,预计可能是虚拟机 cpu 配置问题,后面提到了,hyperscan 与 intel 深度绑定。
批改过 cmake/build_wrapper.sh 脚本后,就能够执行 cmake 命令了
为避免产生的 cmake 文件搞混了源文件,这里倡议建设一个新的目录,执行 cmake
须要留神的是,在应用 hyperscan 时,动静库要比动态库应用绝对不便,批改 CMakeCache.txt 文件,依据版本不同,所在行数也不同。
BUILD_STATIC_AND_SHARED:BOOL=OFF
->
BUILD_STATIC_AND_SHARED:BOOL=ON
批改过后即可执行 make && make install
hyperscan 简略应用
hyperscan 整体的应用流程次要分为编译器和运行期
编译期
编译器次要是将编辑好的正则,编译成数据库供后续应用,
次要包含三个函数,别离实用不同的应用场景
- hs_compile() 将单个规定编译成数据库。
- hs_compile_multi() 将一组规定编译成数据库。
- hs_compile_ext_multi() 将一组规定编译成数据库,并反对扩大参数。
具体细节能够参考《深入浅出 Hyperscan: 高性能正则表达式算法原理与设计》
本例设计应用 hs_compile_multi() 应该是最罕用的函数,普适性较高
-
定义宏,不便后续应用
enum { HYPERSCAN_ID_NONE = 0, HYPERSCAN_ID_TEST1, HYPERSCAN_ID_TEST2,HYPERSCAN_ID_MAX };
-
定义数据结构
/** * 将数据库中待编译的信息保留到这个数组外面 */ typedef struct CompilePatternArray {uint32_t ids[20]; /**< id */ uint32_t flag[20]; /**< 编译参数 */ const char *exps[20]; /**< 正则 */ } CompilePatternArray_t; /** * 编译数据结构 */ typedef struct CompilePattern { uint32_t ids; const char *exps; } CompilePattern_t;
-
应用数组定义一组正则规定
/** * 编译到数据库中的匹配字段,* hyperscan 编译阶段有一个特殊字符本义的过程 */ static const CompilePattern_t gCompilePattern[] = {{HYPERSCAN_ID_NONE, " "}, {HYPERSCAN_ID_TEST1, "123.{1,3}abc"}, {HYPERSCAN_ID_TEST2, "max"} };
-
编译
/** * * @param CompPatt * 待编译信息 * @param count * 数据条数 * @param pDatabase * 数据库 * @return * 返回值,临时没定义 */ static int CompilePatterns(CompilePattern_t *CompPatt, uint32_t count, hs_database_t **pDatabase) { hs_error_t error; hs_compile_error_t *ComError; CompilePatternArray_t compilePattern; // 一对一存储,转存 int i; for (i = 0; i < count; i++) {compilePattern.ids[i] = CompPatt[i].ids; compilePattern.exps[i] = CompPatt[i].exps; compilePattern.flag[i] = HS_FLAG_CASELESS; // 疏忽大小写 } // 编译 /** * 参数阐明 * 1. 正则 * 2. 正则匹配标签 * 3. id * 4. 数量 * 5. 匹配模式 * 6. platform 须要深刻去理解一下,目前置 NULL * 7. 数据库指针 * 8. errorInfo */ error = hs_compile_multi(compilePattern.exps, compilePattern.flag, compilePattern.ids, count, HS_MODE_BLOCK, NULL, pDatabase, (hs_compile_error_t **) &ComError); if (error != HS_SUCCESS) { // 失败的话给出相应的提示信息 std::cout << "compile failed error code is" << error << std::endl; } return 0; }
运行期
hypersacn 运行过程中,进行正则匹配会有一个中间状态暂存匹配信息,须要创立一个 scratch 空间
hs_alloc_scratch(HsDatabase, (hs_scratch_t **) &HsStra);
运行期分为块模式,流模式,向量模式,块模式能够简略的了解为就一次数据输出,输入后果,流模式次要针对网络字节流,但相较于块模式,减少了流开启与敞开的过程,在编译期须要编译的内容也有所区别,本例中次要是块模式样例,流模式,有趣味能够自行钻研。
应用
hs_scan() 进行匹配,调用时须要规定回调函数
/** 参数阐明
* 1. 数据库
* 2. 待匹配字符串
* 3. 字符串长度
* 4. flag,未定义,官网阐明待用
* 5. scratch
* 6. 回调函数
* 7. 回调函数传参
*/
hs_scan(HsDatabase, tmpString, strlen(tmpString), 0, HsStra, onMatch, tmpString);
回调函数
/**
* 回调函数
* @param id
* 匹配字段的 id
* @param from
* 从哪里还是匹配的
* @param to
* 匹配到哪里完结(指向尾部)* @param flags
* 基本没用, hyperscan 官网明确阐明没有应用的参数。* @param ctx
* 回调参数
* @return
* 临时没用
*/
static int onMatch(unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, void *ctx) {char *tmp = (char *) ctx;
std::cout << "id is" << id << std::endl;
switch (id) {
case HYPERSCAN_ID_NONE:
std::cout << std::endl;
break;
case HYPERSCAN_ID_TEST1:
std::cout << "form:" << tmp + from << std::endl;
std::cout << "to:" << tmp + to << std::endl;
std::cout << std::endl;
break;
case HYPERSCAN_ID_TEST2:
std::cout << "form:" << tmp + from << std::endl;
std::cout << "to:" << tmp + to << std::endl;
std::cout << std::endl;
break;
default:
std::cout << "can not found any subString" << std::endl;
break;
}
return 0;
}
传入字符串
abc123123123abcmax123123bacbacabc\0
执行成果
后记
hyperscan 作为一个高性能正则匹配工具,利用场景很多,王翔学生等用几百页文字具体介绍了 hyperscan 基本原理,算法过程与高级个性,但真正应用还须要真正去实际能力真正了解,并且用好这个工具
残缺代码放在了 gitee 上,欢送大家补充,斧正。
https://gitee.com/wang-xiaotian-1/MyHyperscanTest.git