您的位置:首页 > 其它

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

2011-02-20 15:33 351 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: