VC使用DEELX正则引擎-DLL方式

DEELX 是一个在 C++ 环境下的与 Perl 兼容的正则表达式引擎。是 RegExLab 开展的一个研究开发项目。相比于GRETA很Boost来说是一个接口相对简单易用的正在引擎。其基本特点:


支持与 Perl 兼容的正则表达式语法。
支持 IGNORECASE, SINGLELINE, MULTILINE 等常见匹配模式。
兼容性强,能在 vc6, vc7, vc8, gcc, Turbo C++ 等大多数 C++ 环境编译。
支持命名分组,条件表达式,递归表达式等多种高级特性。(1.2版本新特点)

 

与 GRETA、boost 相比,DEELX 独到之处:


完全使用模版库编写,支持 char, wchar_t, int 等以及其他基类型版本。
全部代码位于一个头文件(.h)中, 比任何引擎都使用简单和方便。
支持从右向左匹配模式,可从文本结束位置向前搜索匹配。
可防止零长度子匹配循环无限次而产生的死循环。(1.2版本新特点)

 

这是RegExLab的说法。我们使用还是要根据自己的项目要求合理选择。后续将会做一个GRETA Demo,可做一些对比。DEELX本身只是由一个头文件构成,全是模板,里面实现了一个内部的内存管理模块,感兴趣的可以自己阅读。使用DLL需要一个头文件,DEELX也进行了封装。我们先看看头文件的内容。

 

// flags #ifndef _REGEX_FLAGS_DEFINED enum REGEX_FLAGS { NO_FLAG = 0, SINGLELINE = 0x01, MULTILINE = 0x02, GLOBAL = 0x04, IGNORECASE = 0x08, RIGHTTOLEFT = 0x10, EXTENDED = 0x20, }; #define _REGEX_FLAGS_DEFINED #endif

 

首先定义一些标志位,默认是0。例如SINGLELINE,MULTLINE定义了单行和多行匹配。

 

#ifdef LIBDEELX_EXPORTS #define DEELX_API __declspec( dllexport ) #else #define DEELX_API __declspec( dllimport ) #endif

 

封装一下DLL导出导入关键字,DLL源文件中使用的是__declspec(dllexport)。使用此DLL的源文件中应该使用__declspec(dllixport)。通过开关宏LIBDEELX_EXPORTS区分。

 

其后又用宏LOAD_DEELX_RUNTIME来区分是运行时或非运行时,运行时声明需要导出的函数表,非运行时使用typedef定义了许多函数指针类型,可以简化引入头文件时的工作。我们不选用。

 

// create & free DEELX_API regexp_handle __stdcall regexp_create (); DEELX_API regexp_handle __stdcall regexpw_create(); DEELX_API result_handle __stdcall result_create (); DEELX_API void __stdcall regexp_free (regexp_handle handle); DEELX_API void __stdcall regexpw_free (regexp_handle handle); DEELX_API void __stdcall result_free (result_handle result); // compile & match DEELX_API void __stdcall regexp_compile (regexp_handle handle, const char * pattern, int flag); DEELX_API void __stdcall regexpw_compile (regexp_handle handle, const unsigned short * pattern, int flag); DEELX_API void __stdcall regexp_match (regexp_handle handle, const char * text , int startpos, result_handle result); DEELX_API void __stdcall regexpw_match (regexp_handle handle, const unsigned short * text , int startpos, result_handle result); DEELX_API int __stdcall regexp_replace (regexp_handle handle, const char * text , const char * replaceto, int startpos, int times, char * buffer, int bufsize); DEELX_API int __stdcall regexpw_replace (regexp_handle handle, const unsigned short * text , const unsigned short * replaceto, int startpos, int times, unsigned short * buffer, int bufsize); // get result DEELX_API int __stdcall regexp_namednumber (regexp_handle handle, const char * name); DEELX_API int __stdcall regexpw_namednumber(regexp_handle handle, const unsigned short * name); DEELX_API int __stdcall result_ismatched (result_handle result); DEELX_API int __stdcall result_start (result_handle result); DEELX_API int __stdcall result_end (result_handle result); DEELX_API int __stdcall result_maxgroup (result_handle result); DEELX_API int __stdcall result_groupstart (result_handle result, int number); DEELX_API int __stdcall result_groupend (result_handle result, int number);

 

函数指针类型:

 

// create & free typedef regexp_handle (__stdcall * fn_regexp_create )(); typedef regexp_handle (__stdcall * fn_regexpw_create)(); typedef result_handle (__stdcall * fn_result_create )(); typedef void (__stdcall * fn_regexp_free )(regexp_handle handle); typedef void (__stdcall * fn_regexpw_free )(regexp_handle handle); typedef void (__stdcall * fn_result_free )(result_handle result); // compile & match typedef void (__stdcall * fn_regexp_compile )(regexp_handle handle, const char * pattern, int flag); typedef void (__stdcall * fn_regexpw_compile )(regexp_handle handle, const unsigned short * pattern, int flag); typedef void (__stdcall * fn_regexp_match )(regexp_handle handle, const char * text , int startpos, result_handle result); typedef void (__stdcall * fn_regexpw_match )(regexp_handle handle, const unsigned short * text , int startpos, result_handle result); typedef int (__stdcall * fn_regexp_replace )(regexp_handle handle, const char * text , const char * replaceto, int startpos, int times, char * buffer, int bufsize); typedef int (__stdcall * fn_regexpw_replace )(regexp_handle handle, const unsigned short * text , const unsigned short * replaceto, int startpos, int times, unsigned short * buffer, int bufsize); // get result typedef int (__stdcall * fn_regexp_namednumber )(regexp_handle handle, const char * name); typedef int (__stdcall * fn_regexpw_namednumber)(regexp_handle handle, const unsigned short * name); typedef int (__stdcall * fn_result_ismatched )(result_handle result); typedef int (__stdcall * fn_result_start )(result_handle result); typedef int (__stdcall * fn_result_end )(result_handle result); typedef int (__stdcall * fn_result_maxgroup )(result_handle result); typedef int (__stdcall * fn_result_groupstart )(result_handle result, int number); typedef int (__stdcall * fn_result_groupend )(result_handle result, int number);

 

VC中经常发现不一致的命名方式,Windows使用的匈牙利命名方式与源文件不符,而且我们做个简单的Demo用不着那么多函数指针。所有自己定义几个需要的即可。

 

typedef regexp_handle (__stdcall *RegexpCreate)(); typedef result_handle (__stdcall *ResultCreate)(); typedef void (__stdcall *RegexpFree)(regexp_handle); typedef void (__stdcall *ResultFree)(result_handle) ; typedef void (__stdcall *RegexpCompile)(regexp_handle, const char *, int); typedef void (__stdcall *RegexpMatch)(regexp_handle, const char * , int , result_handle); typedef int (__stdcall *ResultIsmatched)(result_handle); typedef int (__stdcall *ResultStart)(result_handle); typedef int (__stdcall *ResultEnd)(result_handle);

 

__stdcall一定要放在括号内,不然编译器在第一个空格开始把后面的当做需要定义的,语法错误。

 

写一个main函数,首先加载DLL,然后获取DLL中的函数位置,相当于了初始化函数指针。然后验证正在表达式,最后卸载DLL。

 

int main(int argc, char** argv){ if (argc != 3) { printf("input error!/nformat: coretest regular string /n"); return 0; } HINSTANCE hDll =LoadLibrary("libdeelx.dll"); RegexpCreate create =(RegexpCreate)GetProcAddress(hDll,"regexp_create"); ResultCreate createResult =(ResultCreate)GetProcAddress(hDll,"result_create"); RegexpFree regexpFree = (RegexpFree)GetProcAddress(hDll, "regexp_free"); ResultFree resultFree = (ResultFree)GetProcAddress(hDll, "result_free"); RegexpCompile compile = (RegexpCompile)GetProcAddress(hDll, "regexp_compile"); RegexpMatch match = (RegexpMatch)GetProcAddress(hDll, "regexp_match"); ResultIsmatched isMathched = (ResultIsmatched)GetProcAddress(hDll, "result_ismatched"); ResultStart start = (ResultStart)GetProcAddress(hDll, "result_start"); ResultEnd end = (ResultEnd)GetProcAddress(hDll, "result_end"); regexp_handle h = create(); result_handle r = createResult(); compile(h, *(argv + 1), 0); match(h, *(argv + 2), 0, r); printf("%s match %s result : %d", *(argv + 1), *(argv + 2), isMathched(r)); regexpFree(h); resultFree(r); FreeLibrary(hDll); return 0; }

 

如果没有__stdcall会怎么样?悲剧地看到这样的错误- The value of ESP was not properly saved across a function call.  This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.为什么呢?因为VC默认使用_cdecl,而DLL中使用的是_stdcall,栈到底谁清就搞乱了,能乱来么?

 

如果DLL名字写错了怎么样?悲剧地看到访问错误。为什么呢?因为函数指针都指向的0x0000000位置,当然错啦。

 

你可以从Codeproject上下载源码。

 

http://www.codeproject.com/KB/library/deelx.aspxs

你可能感兴趣的:(VC使用DEELX正则引擎-DLL方式)