hyperscan 作为和intel深度绑定的政策匹配工具,提供了及其弱小的正则匹配性能,并提供接口,不便对匹配后果进行二次操作。

我在学习hyperscan时,在各大论坛并没有找到比拟齐备并且具体解说,很多只是提到了函数库大略时干什么的,索性将本人理解到的货色,具体的记录下来,也算是本人对hyperscan的一次坚固

hyperscan 是英特尔开源的一款正则匹配工具,与intel芯片深度绑定,intel对其有专门的优化,因而在整体的匹配效率上,相较于其余正则计划,处于一个较为当先的地位。 hyperscan反对pcre 正则规定,现有的次要利用计划大都是基于pcre做的匹配。

样例代码放在了github上,前面会贴出来。

注: 本文演示环境为 ubuntu 22.04

hyperscan下载安装

  1. 下载
    intel在github上凋谢了源码,通过git即可下载,因为github,在国内拜访不敌对,在gitee上也有相干开源代码
githubgit clone https://github.com/intel/hyperscan.gitgiteegit clone https://gitee.com/tzichengchew/hyperscan.git
  1. 依赖
    hyperscan 应用cmake编译cmake等根底库装置不再赘述, 须要依赖
  2. 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地址

  1. 装置

装置boost

  bash bootstrap.sh && ./b2 && ./b2 install 

装置ragel
不倡议编译装置,坑很多

sudo apt install ragel

编译装置hyperscan
创立一个目录

mkdir hyperscan_comp

执行编译命令

cmake $HYPERSCAN_PATHmake && 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() 应该是最罕用的函数,普适性较高

  1. 定义宏,不便后续应用

    enum { HYPERSCAN_ID_NONE = 0, HYPERSCAN_ID_TEST1, HYPERSCAN_ID_TEST2, HYPERSCAN_ID_MAX};
  2. 定义数据结构

    /*** 将数据库中待编译的信息保留到这个数组外面*/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;
  3. 应用数组定义一组正则规定

    /*** 编译到数据库中的匹配字段,* hyperscan编译阶段有一个特殊字符本义的过程*/static const CompilePattern_t gCompilePattern[] = {     {HYPERSCAN_ID_NONE,  " "},     {HYPERSCAN_ID_TEST1, "123.{1,3}abc"},     {HYPERSCAN_ID_TEST2, "max"}};
  4. 编译

    /**** @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