从v0.14.0版本开始,在编译时,可以添加pcre正则表达式模块,从而可以进行正则匹配,正则替换相关的操作,只要在make命令后面加入USE_PCRE=yes即可。
页面导航:
zenglServer源代码的相关地址:https://github.com/zenglong/zenglServer 当前版本对应的tag标签为:v0.14.0
从v0.14.0版本开始,在编译时,可以添加pcre正则表达式模块。从而可以进行正则匹配,正则替换相关的操作。只要在make命令后面加入USE_PCRE=yes即可。
当然,要使用pcre模块,前提是系统中安装了底层的pcre开发库。
如果是ubuntu系统,可以通过 sudo apt-get install libpcre3 libpcre3-dev 来安装pcre相关的库和开发头文件等:
zengl@zengl-ubuntu:~$ sudo apt-get install libpcre3 libpcre3-dev
如果是centos系统,则可以通过 yum install pcre pcre-devel 来安装相关的底层库:
[root@localhost ~]# yum install pcre pcre-devel
要同时使用mysql,magick和pcre模块,可以使用 make USE_MYSQL=yes USE_MAGICK=6 USE_PCRE=yes 命令:
zengl@zengl-ubuntu:~/zenglServer$ make USE_MYSQL=yes USE_MAGICK=6 USE_PCRE=yes ............................................................................ gcc -g3 -ggdb -O0 -std=c99 main.c http_parser.c module_request.c module_builtin.c module_session.c dynamic_string.c multipart_parser.c resources.c client_socket_list.c json.c randutils.c md5.c debug.c main.h http_parser.h common_header.h module_request.h module_builtin.h module_session.h dynamic_string.h multipart_parser.h resources.h client_socket_list.h json.h randutils.h md5.h debug.h module_mysql.c module_mysql.h module_magick.c module_magick.h module_pcre.c module_pcre.h zengl/linux/zengl_exportfuns.h -o zenglServer zengl/linux/libzengl.a crustache/libcrustache.a -lpthread -lm -DUSE_MYSQL `mysql_config --cflags --libs` -D USE_MAGICK=6 `pkg-config --cflags --libs Wand` -DUSE_PCRE `pcre-config --cflags --libs` mysql module is enabled!!! magick module is enabled!!! pcre module is enabled!!! zengl@zengl-ubuntu:~/zenglServer$
和pcre正则表达式模块相关的C源码位于module_pcre.c文件中:
/* * module_pcre.c * * Created on: Nov 2, 2018 * Author: zengl */ ................................................................ /** * 将正则匹配和正则替换模块函数中的第四个modifier参数,从字符串格式转为对应的pcre选项 * modifier中的字符'i',会转为PCRE_CASELESS选项,表示正则匹配时,忽略大小写 * modifier中的字符's',会转为PCRE_DOTALL选项,表示正则匹配时,'.'点字符能匹配任意字符,包括换行符 * modifier中的字符'm',会转为PCRE_MULTILINE选项,表示正则匹配时,^和$能匹配多行字符串中的任意一行的起始和结束位置 */ static int st_pcre_get_options(ZL_EXP_VOID * VM_ARG, int arg_index, ZENGL_EXPORT_MOD_FUN_ARG * arg, const char * function_name) { ................................................................ } ................................................................ /** * pcreMatch模块函数,通过正则表达式进行匹配,只匹配一次,返回值为0表示没匹配到,返回值大于0表示匹配到了, * 该模块函数的第一个参数pattern表示需要匹配的正则表达式,第二个参数subject表示需要匹配的主体内容, * 第三个参数result_array以数组的形式存储匹配的结果,匹配结果中,第一个成员表示匹配到的包括各分组在内的完整字符串, * result_array第二个成员表示匹配到的索引值为1的第一个分组,第三个成员表示匹配到的索引值为2的第二个分组,以此类推。 * 由于result_array要存储匹配的结果,因此,必须是引用类型, * 第四个参数modifier是可选的,表示额外的匹配选项,例如,当modifier中包含字符'i'时,表示忽略大小写等, * 例如: * use builtin, request, pcre; * rqtSetResponseHeader("Content-Type: text/html; charset=utf-8"); * ret = pcreMatch('^(\d+)\s+<Title>(.*?)</Title>$', 'hello\n\n112 <title>世界你好吗\n!</title>', &results, 'ism'); * if(!ret) * print 'no match'; * else * for(i=0;bltIterArray(results,&i,&k, &v);) * print k + '):' + v; * endfor * endif * 得到的结果是: * 0):112 <title>世界你好吗 * !</title> * 1):112 * 2):世界你好吗 * ! */ ZL_EXP_VOID module_pcre_match(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount) { ................................................................ } /** * pcreMatchAll模块函数,通过正则表达式进行匹配, * 该模块函数与pcreMatch的区别是,它能匹配到所有的字符串,而不像pcreMatch只匹配一次, * pcreMatchAll和pcreMatch的参数是一样的,参数的含义可以参考pcreMatch模块函数, * pcreMatchAll匹配的结果和pcreMatch一样存储在result_array数组中, * 只不过该模块函数的result_array是一个二维数组,也就是说,result_array的每个成员都是一个数组, * 索引值为0的第一个成员对应的数组中,都存储的是匹配到的完整的字符串, * 索引值为1的第二个成员对应的数组中,都存储的是第一个分组的字符串, * 索引值为2的第三个成员对应的数组中,都存储的是第二个分组的字符串,以此类推 * 例如: use builtin, request, pcre; rqtSetResponseHeader("Content-Type: text/html; charset=utf-8"); ret = pcreMatchAll('^(\d+)\s+<Title>(.*?)</Title>$', 'hello\n\n112 <title>世界你好吗\n!!</title>\n3223 <TItle>~~hello world哈哈~~</TItle>', &results, 'ism'); if(!ret) print 'no match'; else for(i=0;bltIterArray(results,&i,&k, &v);) // print k + '):' + v; print k + '):'; for(j=0;bltIterArray(v, &j, &kk, &vv);) print '['+ kk + ']:' + vv; endfor endfor print ''; for(j=0;bltIterArray(results[2], &j, &kk, &vv);) print '['+ kk + ']:' + vv; endfor endif * 得到的结果会是: 0): [0]:112 <title>世界你好吗 !!</title> [1]:3223 <TItle>~~hello world哈哈~~</TItle> 1): [0]:112 [1]:3223 2): [0]:世界你好吗 !! [1]:~~hello world哈哈~~ [0]:世界你好吗 !! [1]:~~hello world哈哈~~ */ ZL_EXP_VOID module_pcre_match_all(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount) { ................................................................ } /** * pcreReplace模块函数,通过正则表达式执行替换操作 * 该模块函数的第一个参数pattern表示需要匹配的正则表达式,第二个参数replace表示需要进行替换的字符串, * 第三个参数subject表示需要进行匹配和替换的主体字符串,第四个参数modifier是可选的,表示额外的匹配选项, * 第五个参数use_capture也是可选的,表示replace参数中的{1},{2}等是否需要被替换为对应的分组,默认是1,表示需要替换, * 第六个参数replace_num也是可选的,表示需要替换多少个字符串,默认为-1,表示全部替换,如果为1表示替换1个,为2表示替换前2个,以此类推。 * 当use_capture是不为0的值时,replace中的{0}表示替换为匹配的完整字符串,{1}表示替换为匹配到的第一个分组,{2}表示替换为匹配到的第二个分组等 * replace中的'^'字符可以转义'{',从而让{1}等变为普通的字符串,例如:'^{1}'就表示'{1}'的普通字符串,'^'还会将自己转义,'^^'表示一个'^', * 转义操作也发生在use_capture不为0的时候,如果use_capture为0,则不会有分组替换操作,也不会有replace的转义操作, * * 该模块函数的使用,可以参考下面的例子: use builtin, request, pcre; def TRUE 1; def FALSE 0; rqtSetResponseHeader("Content-Type: text/html; charset=utf-8"); ret = pcreReplace('^(\d+)\s+<Title>(.*?)</Title>$', '[title]^^^{1}{2}[/title]', 'hello\n\n112 <title>世界你好吗\n!!</title>\n3223 <TItle>~~hello world哈哈~~</TItle>', 'ism'); print ret; print ''; ret = pcreReplace('^(\d+)\s+<Title>(.*?)</Title>$', '[title]^^^{1}{2}[/title]', 'hello\n\n112 <title>世界你好吗\n!!</title>\n3223 <TItle>~~hello world哈哈~~</TItle>', 'ism', FALSE); print ret; print ''; ret = pcreReplace('^(\d+)\s+<Title>(.*?)</Title>$', '[title]^^{1}{2}[/title]', 'hello\n\n112 <title>世界你好吗\n!!</title>\n3223 <TItle>~~hello world哈哈~~</TItle>', 'ism', TRUE, 1); print ret; * 上面得到的结果会是: hello [title]^{1}世界你好吗 !![/title] [title]^{1}~~hello world哈哈~~[/title] hello [title]^^^{1}{2}[/title] [title]^^^{1}{2}[/title] hello [title]^112世界你好吗 !![/title] 3223 <TItle>~~hello world哈哈~~</TItle> */ ZL_EXP_VOID module_pcre_replace(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount) { ................................................................ } /** * pcre模块的初始化函数,里面设置了与该模块相关的各个模块函数及其相关的处理句柄 */ ZL_EXP_VOID module_pcre_init(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT moduleID) { zenglApi_SetModFunHandle(VM_ARG,moduleID,"pcreMatch",module_pcre_match); zenglApi_SetModFunHandle(VM_ARG,moduleID,"pcreMatchAll",module_pcre_match_all); zenglApi_SetModFunHandle(VM_ARG,moduleID,"pcreReplace",module_pcre_replace); }
在my_webroot的v0_14_0目录中,增加了三个测试脚本test.zl,test_all.zl以及test_replace.zl,这三个测试脚本分别演示了pcreMatch,pcreMatchAll和pcreReplace模块函数的使用。
其中,my_webroot/v0_14_0目录中的test.zl脚本的源码如下:
use builtin, request, pcre; rqtSetResponseHeader("Content-Type: text/html; charset=utf-8"); ret = pcreMatch('^(\d+)\s+<Title>(.*?)</Title>$', 'hello\n\n112 <title>世界你好吗\n!</title>', &results, 'ism'); if(!ret) print 'no match'; else for(i=0;bltIterArray(results,&i,&k, &v);) print k + '):' + v; endfor endif
上面脚本中,pcreMatch的第一个参数'^(\d+)\s+<Title>(.*?)</Title>$'表示需要进行匹配的正则表达式,第二个参数'hello\n\n112 <title>世界你好吗\n!</title>'表示需要匹配的主体内容。
pcreMatch会根据正则表达式对主体内容进行匹配,匹配的结果存储在第三个参数results中。
最后一个参数'ism'是额外的正则表达式匹配修饰符(该参数是可选的),i表示忽略大小写,s表示点符号匹配包括换行符在内的所有字符,m表示^和$能匹配多行字符串。
如果pcreMatch返回0,表示没有匹配到数据,大于0表示匹配到了数据,当匹配到数据时,就通过循环语句将results结果数组打印出来。上面脚本的执行结果如下:
zengl@zengl-ubuntu:~/zenglServer$ curl http://127.0.0.1:8083/v0_14_0/test.zl 0):112 <title>世界你好吗 !</title> 1):112 2):世界你好吗 ! zengl@zengl-ubuntu:~/zenglServer$
可以看到,匹配的结果数组中,索引值为0的第一个成员是匹配到的完整字符串,索引值为1的第二个成员是匹配到的第一个分组,索引值为2的第三个成员是匹配到的第二个分组。
my_webroot/v0_14_0目录中的test_all.zl脚本的内容如下:
use builtin, request, pcre; rqtSetResponseHeader("Content-Type: text/html; charset=utf-8"); ret = pcreMatchAll('^(\d+)\s+<Title>(.*?)</Title>$', 'hello\n\n112 <title>世界你好吗\n!!</title>\n3223 <TItle>~~hello world哈哈~~</TItle>', &results, 'ism'); if(!ret) print 'no match'; else for(i=0;bltIterArray(results,&i,&k, &v);) // print k + '):' + v; print k + '):'; for(j=0;bltIterArray(v, &j, &kk, &vv);) print '['+ kk + ']:' + vv; endfor endfor print ''; for(j=0;bltIterArray(results[2], &j, &kk, &vv);) print '['+ kk + ']:' + vv; endfor endif
可以看到,pcreMatchAll模块函数与pcreMatch模块函数的参数是一样的,只不过第三个参数results结果数组中存储的是二维数组,也就是该数组中的每个成员又都是一个数组。所以,上面脚本中使用了双层for循环来打印results中的数据。
该脚本执行的结果如下:
zengl@zengl-ubuntu:~/zenglServer$ curl http://127.0.0.1:8083/v0_14_0/test_all.zl 0): [0]:112 <title>世界你好吗 !!</title> [1]:3223 <TItle>~~hello world哈哈~~</TItle> 1): [0]:112 [1]:3223 2): [0]:世界你好吗 !! [1]:~~hello world哈哈~~ [0]:世界你好吗 !! [1]:~~hello world哈哈~~ zengl@zengl-ubuntu:~/zenglServer$
返回的结果中,results数组的索引值为0的第一个成员对应的数组中,存储的都是匹配到的完整字符串。索引值为1的第二个成员对应的数组中,存储的都是匹配到的第一个分组。索引值为2的第三个成员对应的数组中,存储的都是匹配到的第二个分组。
my_webroot/v0_14_0目录中的test_replace.zl脚本的内容如下:
use builtin, request, pcre; def TRUE 1; def FALSE 0; rqtSetResponseHeader("Content-Type: text/html; charset=utf-8"); ret = pcreReplace('^(\d+)\s+<Title>(.*?)</Title>$', '[title]^^^{1}{2}[/title]', 'hello\n\n112 <title>世界你好吗\n!!</title>\n3223 <TItle>~~hello world哈哈~~</TItle>', 'ism'); print ret; print ''; ret = pcreReplace('^(\d+)\s+<Title>(.*?)</Title>$', '[title]^^^{1}{2}[/title]', 'hello\n\n112 <title>世界你好吗\n!!</title>\n3223 <TItle>~~hello world哈哈~~</TItle>', 'ism', FALSE); print ret; print ''; ret = pcreReplace('^(\d+)\s+<Title>(.*?)</Title>$', '[title]^^{1}{2}[/title]', 'hello\n\n112 <title>世界你好吗\n!!</title>\n3223 <TItle>~~hello world哈哈~~</TItle>', 'ism', TRUE, 1); print ret;
pcreReplace模块函数的第一个参数是需要匹配的正则表达式。
第二个参数是当匹配到数据时,需要替换的字符串,替换字符串中可以使用{0}表示匹配到的完整字符串,{1}表示匹配到的第一个分组,{2}表示匹配到的第二个分组,以此类推。
第三个参数是需要进行匹配和替换的主体字符串(模块函数会对该主体字符串执行正则匹配和替换操作),第四个参数是可选的,表示额外的正则匹配修饰符。
第五个参数也是可选的,表示是否将第二个参数即替换字符串里的{0},{1}等替换为匹配到的分组信息,该参数默认是1,表示需要替换,如果为0则表示不替换,当该参数为0时,就相当于不对第二个参数进行任何处理,直接替换过去。
第六个参数(可选参数)表示需要替换的次数,默认是-1表示对所有匹配到的字符串都执行替换操作,如果为1,则表示只替换一次,为2,表示只替换两次,以此类推。
在该模块函数的第二个替换字符串参数中,可以使用'^'符号对'{'进行转义,使其变为普通的'{',这样转义后的'{1}'就是普通的字符串了,不会被替换为对应的分组。'^'符号还会对自己进行转义,两个'^'在一起:'^^'即表示一个'^'符号。所以上面脚本中的'^^^{1}'对应的替换结果就是'^{1}',两个'^'变为了一个'^','^{'变为了普通的'{'。如果第五个参数为0,则不会有分组替换操作,也不会有转义操作。
pcreReplace会将替换后的结果字符串返回,如果正则表达式没有匹配到任何数据,则会将原字符串返回,上面脚本的执行结果如下:
zengl@zengl-ubuntu:~/zenglServer$ curl http://127.0.0.1:8083/v0_14_0/test_replace.zl hello [title]^{1}世界你好吗 !![/title] [title]^{1}~~hello world哈哈~~[/title] hello [title]^^^{1}{2}[/title] [title]^^^{1}{2}[/title] hello [title]^112世界你好吗 !![/title] 3223 <TItle>~~hello world哈哈~~</TItle> zengl@zengl-ubuntu:~/zenglServer$
以上就是当前版本的相关内容,休息,休息一下。
只要有梦想,什么都能实现
—— 《创世纪》