从v0.14.0版本开始,在编译时,可以添加pcre正则表达式模块,从而可以进行正则匹配,正则替换相关的操作,只要在make命令后面加入USE_PCRE=yes即可。

    页面导航:

项目下载地址:

    zenglServer源代码的相关地址:https://github.com/zenglong/zenglServer  当前版本对应的tag标签为:v0.14.0

zenglServer 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$ 

    以上就是当前版本的相关内容,休息,休息一下。

结束语:

    只要有梦想,什么都能实现

—— 《创世纪》

 

上下篇

下一篇: zenglServer v0.15.0 - v0.15.1 增加curl模块,用于执行数据抓取操作

上一篇: zenglServer v0.13.0 目录入口文件以及模板路径调整

相关文章

zenglServer v0.22.0 增加支付宝支付测试脚本,增加bltUrlEncode等模块函数

zenglServer v0.13.0 目录入口文件以及模板路径调整

zenglServer v0.18.0 直接在命令行中执行脚本

zenglServer v0.11.0 共享内存,crustache转义,magick模块,新增bltDate等内建模块函数

zenglServer v0.19.0 增加redis缓存相关的模块

zenglServer v0.10.1 添加bltInt,bltFloat,bltHtmlEscape模块函数,使用v1.8.1版本的zengl语言库