C:基于GNU regex(regex.h)regexec实现正则表达式多次匹配

GNU regex是GNU提供的跨平台的POSIX 正则表达式库(C语言)。
不算GNU提供的扩展函数,POSIX标准的regex库总共就4个函数regcomp,regerror,regexec,regfree.
我们知道 regexec 不能通过一次调用找到字符串中所有满足匹配条件的字符串位置,所以需要通过步进偏移的方式循环执行regexec才能把字符串中所有满足条件的匹配找出来, 每一次匹配的起始偏移是上一次匹配到的字符串结束偏移。

在上一篇博客《C: GNU regex library (regex.h)正则表达式调用示例》中,我已经 实现了正则表达式匹配多个捕获组(catch group),并且循环执行regexec实现多次实现。本文就是对上一次的实现进行改进,将循环匹配逻辑进一步封装成易用的函数rx_search.

做这个封装对于我的现实意义是,最近工作的一个项目运行在嵌入式平台上,设备提供的SDK中有GNU regex库,但是是非常老的版本,只有4个函数regcomp,regerror,regexec,regfree.没有提供高版本才有的re_search函数。所以如果想实现多次匹配,只能自己实现了。

以下是rx_search的实现代码:

rx_serach

//************************************
// 用指定的正则表达式在字符串中查找所有匹配
// @param    const char * input    待匹配的字符串
// @param    const char * pattern  正则表达式
// @param    size_t       groupcnt 正则表达式中捕获组数量(包含默认组group 0),为0时使用默认值,即pattern编译后regex_t的re_nsub+1
//                                 regex_t.re_nsub字段为正则表达式中子表达式的数量,子表达式又分为捕获和非捕获两种.
//                                 所以re_nsub + 1肯定大于等于表达式中所有捕获组(包含默认组group 0)的数量
// @param    int          eflags   正则表达匹配执行标志,参见 regexec
// @param    search_match_t *      _psmatch [out] 保存字符串所有匹配的位置
// @return   int                   匹配成功返回匹配匹配的数量,没有匹配返回0,失败返回-1,
//                                 调用层必须调用rx_search_match_uninit释放分配的空间
//************************************
int rx_serach(const char* input, const char* pattern, size_t groupcnt, int eflags, search_match_t* _psmatch)
{
	if (NULL == input || NULL == pattern || NULL == _psmatch)
	{
		printf("%s:%d NULL ARGUMENT\n",__FILE__,__LINE__);
		return 0;
	}

	regex_t reg;
	/************************************************************************/
	/* 编译正则表达式,编译成功的 regex_t 对象才可以被后续的 regexec 使用    */
	/************************************************************************/
	int c = regcomp(&reg, pattern, REG_EXTENDED);
	if (0 != c)
	{
		/************************************************************************/
		/*  正则表达式编译出错输出错误信息                                      */
		/*  调用 regerror 将错误信息输出到 regerrbuf 中                         */
		/*  regerrbuf 末尾置0,确保上面调用regerror 导致 regerrbuf 溢出的情况下, */
		/*  字符串仍有有结尾0                                                   */
		/*  然后 printf 输出                                                    */
		/************************************************************************/
		regerror(c, &reg, regerrbuf, sizeof(regerrbuf));
		regerrbuf[sizeof(regerrbuf) - 1] = '\0';
		printf("%s:%d %s\n",__FILE__,__LINE__, regerrbuf);
		return -1;
	}
	
	if (0 == groupcnt)
	{
		groupcnt = reg.re_nsub + 1;
	}
	c = rx_search_match_init(_psmatch, groupcnt);
	if (0 != c)
	{
		/** search_match_t 初始化失败,释放前面初始化成功的 regex_t */
		regfree(&reg);
		return c;
	}
	/** 起始匹配的偏移量 */
	size_t offset = 0;
	/************************************************************************/
	/* regexec 不能通过一次调用找到字符串中所有满足匹配条件的字符串位置,    */
	/* 所以需要通过步进偏移的方式循环查找字符串中所有匹配的字符串,          */
	/* 每一次匹配的起始偏移是上一次匹配到的字符串结束偏移                   */
	/************************************************************************/
	do {
		printf("MATCH start %d\n", (int)offset);
		/** 输出缓冲区扩容 */
		regmatch_t* pmatch = rx_search_match_ensure(_psmatch, 1);
		if (NULL == pmatch)
		{
			printf("%s:%d MEMORY ERROR for rx_search_match_ensure\n",__FILE__,__LINE__);
			c = -1;
			break;
		}
		/** 正则表达式匹配的起始地址 */
		const char* p = input + offset;
		/************************************************************************/
		/* regmatch_t 用于记录正则表达匹配的结果,每一个 regmatch_t 记录一个捕获 */
		/* 组(catch group)的在字符串中的起始位置。                              */
		/* 如果调用 regexec 时如果不提供 regmatch_t(nmatch为0,pmatch为NULL),    */
		/* 或者提供的 regmatch_t 数组长小于正则表达式中全部捕获组的数量,        */
		/* regexec 也能正常匹配,只是无法记录匹配的位置                          */
		/* 或不能完全记录所有的匹配结果                                         */
		/************************************************************************/
		c = regexec(&reg, p, _psmatch->groupcnt, pmatch, eflags);
		if (REG_NOMATCH == c)
		{
			/************************************************************************/
			/** 没有找到匹配结束循环                                                */
			/************************************************************************/
			printf("MATCH FINISHED\n");
			break;
		}
		else if (0 == c)
		{
			/** 匹配计数加1 */
			_psmatch->matchcnt++;
			/** 找到匹配,则输出匹配到的所有捕获组(catch group) */
			printf("%d MATCH (%d-%d)\n", (int)_psmatch->matchcnt, pmatch[0].rm_so, pmatch[0].rm_eo);
			for (int i = 0; i < _psmatch->groupcnt; ++i)
			{
				printf("group %d :<<", i);
				print_str(p, pmatch[i].rm_so, pmatch[i].rm_eo);
				printf(">>\n");
			}
			/** (group 0)的结束位置 */
			size_t eo = pmatch[0].rm_eo;
			for (int i = 0; i < _psmatch->groupcnt; ++i)
			{
				/** 偏移量修改为相对于字符串起始位置 */
				pmatch[i].rm_so += (int)offset;
				pmatch[i].rm_eo += (int)offset;
			}
			/************************************************************************/
			/* 使用整体匹配捕获组0(group 0)的结束位置的更新偏移量,                  */
			/* 下一次匹配从当前匹配的结束位置开始                                   */
			/************************************************************************/
			offset += eo;
			continue;
		}
		else
		{
			/************************************************************************/
			/** regexec 调用出错输出错误信息,结束循环                               */
			/************************************************************************/
			regerror(c, &reg, regerrbuf, sizeof(regerrbuf));
			regerrbuf[sizeof(regerrbuf) - 1] = '\0';
			printf("%s\n", regerrbuf);
			c = -1;
			break;
		}
	} while (1);
	printf("%d MATCH FOUND\n", (int)_psmatch->matchcnt);
	/************************************************************************/
	/** regfree 必须与 regcomp 配对使用,否则会发生内存泄露                  */
	/************************************************************************/
	regfree(&reg);
	/** REG_NOMATCH 为正常循环结束标志  */
	if (c != REG_NOMATCH)
	{
		/** 出错时释放 search_match_t 所占内存 */
		rx_search_match_uninit(_psmatch);
		return c;
	}
	return (int)_psmatch->matchcnt;
}

search_match_t

因为我们并不可能预知字符串中有多少满足正则表达式条件的匹配。所以我设计了一个search_match_t结构用来保存匹配的结果数据,rx_search执行结果就保存在search_match_t

/************************************************************************/
/* 保存执行 regexec 多次匹配数据                                        */
/************************************************************************/
typedef struct search_match_t
{
	/** 捕获组数量(包含group 0) */
	size_t groupcnt;
	/** 可保存匹配次数 */
	size_t capacity;
	/** 匹配次数 */
	size_t matchcnt;
	/************************************************************************/
	/* 以在字符串中的顺序保存每一次匹配的数据,                              */
	/* 数组长度为 capacity*groupcnt,                                        */
	/* rx_search在执行时会根据需要自动对数组长度扩容                        */
	/************************************************************************/
	regmatch_t* pmatch;
}search_match_t;

rx_search_match_ensure

因为我们并不可能预知字符串中有多少满足正则表达式条件的匹配,所以在执行rx_search时当匹配数量超过search_match_t.pmatch数组容量时,会根据需要自动对search_match_t.pmatch数组长度扩容,
以下是search_match_t 扩容函数rx_search_match_ensure的实现:

//************************************
// search_match_t 扩容,确保 search_match_t 中有足够的空闲空间保存 freecnt 指定大小的匹配数据
// 扩容部分内存清零
// @param    search_match_t * _psmatch
// @param    size_t           freecnt 要求空闲保存的匹配空间数量(每个匹配需要的regmatch_t数量为groupcnt)
// @return   regmatch_t*      扩容成功返回最后空闲的regmatch_t起始位置,否则返回NULL
//************************************
static regmatch_t* rx_search_match_ensure(search_match_t * _psmatch, size_t freecnt)
{
	regmatch_t *newbuffer = NULL;
	size_t newsize = 0;
	size_t newcapacity = 0;

	if ((_psmatch == NULL) || (_psmatch->pmatch == NULL))
	{
		printf("%s:%d NULL ARGUMENT\n",__FILE__,__LINE__);
		return NULL;
	}

	if ((_psmatch->capacity > 0) && (_psmatch->matchcnt >= _psmatch->capacity))
	{
		printf("%s:%d INVALID matchcnt %d\n",__FILE__,__LINE__,(int)_psmatch->matchcnt);
		return NULL;
	}

	if (freecnt > (INT_MAX / 64))
	{
		printf("%s:%d TOO LARGE ARGUMENT matchcnt %d\n",__FILE__,__LINE__,(int)freecnt);
		return NULL;
	}

	if (freecnt <= (_psmatch->capacity - _psmatch->matchcnt))
	{
		return _psmatch->pmatch + (_psmatch->matchcnt * _psmatch->groupcnt);
	}

	/** 以16整数倍扩容 */
	newcapacity = ((freecnt + _psmatch->matchcnt + 16 - 1) >> 4 << 4);
	newsize = newcapacity * _psmatch->groupcnt * sizeof(regmatch_t);

	/* reallocate with realloc if available */
	newbuffer = (regmatch_t*)realloc(_psmatch->pmatch, newsize);
	if (newbuffer == NULL)
	{
		printf("%s:%d MEM ERROR\n",__FILE__,__LINE__);
		free(_psmatch->pmatch);
		_psmatch->capacity = 0;
		_psmatch->groupcnt = 0;
		_psmatch->matchcnt = 0;
		_psmatch->pmatch = NULL;

		return NULL;
	}
	size_t oldsize =                _psmatch->matchcnt  * _psmatch->groupcnt * sizeof(regmatch_t);
	size_t expsize = (newcapacity - _psmatch->matchcnt) * _psmatch->groupcnt * sizeof(regmatch_t);
	/** 扩容部分清零 */
	memset(newbuffer + oldsize, 0, expsize);

	_psmatch->capacity = newcapacity;
	_psmatch->pmatch = newbuffer;
	printf("%s:%d pmatch buffer expand to %d match\n",__FILE__,__LINE__, (int)newcapacity);
	return _psmatch->pmatch + (_psmatch->matchcnt * _psmatch->groupcnt);
}
//************************************
// 释放search_match_t中分配的空间,
// @param    search_match_t * _psmatch
//************************************
void rx_search_match_uninit(search_match_t* _psmatch)
{
	if (_psmatch)
	{
		free(_psmatch->pmatch);
		memset(_psmatch, 0, sizeof(search_match_t));
	}
}

rx_search_match_uninit

rx_search执行后,search_match_t中分配的内存调用者要负责释放
这就需要另外一个函数rx_search_match_uninit来完成search_match_t的释放

//************************************
// 释放search_match_t中分配的空间,
// @param    search_match_t * _psmatch
//************************************
void rx_search_match_uninit(search_match_t* _psmatch)
{
	if (_psmatch)
	{
		free(_psmatch->pmatch);
		memset(_psmatch, 0, sizeof(search_match_t));
	}
}

完整代码

以下是可以用 MSVC/GCC 直接编译运行的完整代码(含测试)

rx_search_test.c

/************************************************************************/
/*  rx_search_test.c                                                    */
/*  GNU Regex 测试                                                      */
/*  rx_search 实现调用regexe多次搜索字符串中满足正则表达式的匹配,       */
/*  并保存到 search_match_t                                             */
/*  author guyadong                                                     */
/************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <regex.h>
#include <limits.h>
#include <string.h>

/** regex 错误输出缓冲区 */
static char regerrbuf[256];

/** 输出字符串中指定范围的字符到控制台 */
void print_str(const char* input, size_t _start, size_t _end)
{
	if (input)
	{
		for (size_t i = _start; i < _end; ++i)
		{
			printf("%c", input[i]);
		}
	}
}

/************************************************************************/
/* 保存执行 regexec 多次匹配数据                                          */
/************************************************************************/
typedef struct search_match_t
{
	/** 捕获组数量(包含group 0) */
	size_t groupcnt;
	/** 可保存匹配次数 */
	size_t capacity;
	/** 匹配次数 */
	size_t matchcnt;
	/************************************************************************/
	/* 以在字符串中的顺序保存每一次匹配的数据,                              */
	/* 数组长度为 capacity*groupcnt,                                        */
	/* rx_search在执行时会根据需要自动对数组长度扩容                        */
	/************************************************************************/
	regmatch_t* pmatch;
}search_match_t;

//************************************
// search_match_t 初始化,以初始容量16分配内存,并将内存清零
// 如果匹配次数超过容量,会调用 rx_search_match_ensure 自动扩容
// @param    search_match_t * _psmatch
// @param    size_t           groupcnt
// @return   int              成功返回0,否则返回-1
//************************************
static int rx_search_match_init(search_match_t* _psmatch,size_t groupcnt)
{
	if(NULL == _psmatch){
		return -1;
	}
	_psmatch->capacity = 16;
	_psmatch->matchcnt = 0;
	_psmatch->groupcnt = groupcnt;
	size_t size = sizeof(regmatch_t) * groupcnt * _psmatch->capacity;
	_psmatch->pmatch = (regmatch_t*)malloc(size);	
	if(!_psmatch->pmatch)
	{
		printf("%s:%d MEM ERROR\n",__FILE__,__LINE__);
		return -1;
	}
	/** 内存清零 */
	memset(_psmatch->pmatch, 0, size);
	return 0;
}
//************************************
// search_match_t 扩容,确保 search_match_t 中有足够的空闲空间保存 freecnt 指定大小的匹配数据
// 扩容部分内存清零
// @param    search_match_t * _psmatch
// @param    size_t           freecnt 要求空闲保存的匹配空间数量(每个匹配需要的regmatch_t数量为groupcnt)
// @return   regmatch_t*      扩容成功返回最后空闲的regmatch_t起始位置,否则返回NULL
//************************************
static regmatch_t* rx_search_match_ensure(search_match_t * _psmatch, size_t freecnt)
{
	regmatch_t *newbuffer = NULL;
	size_t newsize = 0;
	size_t newcapacity = 0;

	if ((_psmatch == NULL) || (_psmatch->pmatch == NULL))
	{
		printf("%s:%d NULL ARGUMENT\n",__FILE__,__LINE__);
		return NULL;
	}

	if ((_psmatch->capacity > 0) && (_psmatch->matchcnt >= _psmatch->capacity))
	{
		printf("%s:%d INVALID matchcnt %d\n",__FILE__,__LINE__,(int)_psmatch->matchcnt);
		return NULL;
	}

	if (freecnt > (INT_MAX / 64))
	{
		printf("%s:%d TOO LARGE ARGUMENT matchcnt %d\n",__FILE__,__LINE__,(int)freecnt);
		return NULL;
	}

	if (freecnt <= (_psmatch->capacity - _psmatch->matchcnt))
	{
		return _psmatch->pmatch + (_psmatch->matchcnt * _psmatch->groupcnt);
	}

	/** 以16整数倍扩容 */
	newcapacity = ((freecnt + _psmatch->matchcnt + 16 - 1) >> 4 << 4);
	newsize = newcapacity * _psmatch->groupcnt * sizeof(regmatch_t);

	/* reallocate with realloc if available */
	newbuffer = (regmatch_t*)realloc(_psmatch->pmatch, newsize);
	if (newbuffer == NULL)
	{
		printf("%s:%d MEM ERROR\n",__FILE__,__LINE__);
		free(_psmatch->pmatch);
		_psmatch->capacity = 0;
		_psmatch->groupcnt = 0;
		_psmatch->matchcnt = 0;
		_psmatch->pmatch = NULL;

		return NULL;
	}
	size_t oldsize =                _psmatch->matchcnt  * _psmatch->groupcnt * sizeof(regmatch_t);
	size_t expsize = (newcapacity - _psmatch->matchcnt) * _psmatch->groupcnt * sizeof(regmatch_t);
	/** 扩容部分清零 */
	memset(newbuffer + oldsize, 0, expsize);

	_psmatch->capacity = newcapacity;
	_psmatch->pmatch = newbuffer;
	printf("%s:%d pmatch buffer expand to %d match\n",__FILE__,__LINE__, (int)newcapacity);
	return _psmatch->pmatch + (_psmatch->matchcnt * _psmatch->groupcnt);
}
//************************************
// 释放search_match_t中分配的空间,
// @param    search_match_t * _psmatch
//************************************
void rx_search_match_uninit(search_match_t* _psmatch)
{
	if (_psmatch)
	{
		free(_psmatch->pmatch);
		memset(_psmatch, 0, sizeof(search_match_t));
	}
}
//************************************
// 用指定的正则表达式在字符串中查找所有匹配
// @param    const char * input    待匹配的字符串
// @param    const char * pattern  正则表达式
// @param    size_t       groupcnt 正则表达式中捕获组数量(包含默认组group 0),为0时使用默认值,即pattern编译后regex_t的re_nsub+1
//                                 regex_t.re_nsub字段为正则表达式中子表达式的数量,子表达式又分为捕获和非捕获两种.
//                                 所以re_nsub + 1肯定大于等于表达式中所有捕获组(包含默认组group 0)的数量
// @param    int          eflags   正则表达匹配执行标志,参见 regexec
// @param    search_match_t *      _psmatch [out] 保存字符串所有匹配的位置
// @return   int                   匹配成功返回匹配匹配的数量,没有匹配返回0,失败返回-1,
//                                 调用层必须调用rx_search_match_uninit释放分配的空间
//************************************
int rx_serach(const char* input, const char* pattern, size_t groupcnt, int eflags, search_match_t* _psmatch)
{
	if (NULL == input || NULL == pattern || NULL == _psmatch)
	{
		printf("%s:%d NULL ARGUMENT\n",__FILE__,__LINE__);
		return 0;
	}

	regex_t reg;
	/************************************************************************/
	/* 编译正则表达式,编译成功的 regex_t 对象才可以被后续的 regexec 使用    */
	/************************************************************************/
	int c = regcomp(&reg, pattern, REG_EXTENDED);
	if (0 != c)
	{
		/************************************************************************/
		/*  正则表达式编译出错输出错误信息                                      */
		/*  调用 regerror 将错误信息输出到 regerrbuf 中                         */
		/*  regerrbuf 末尾置0,确保上面调用regerror 导致 regerrbuf 溢出的情况下, */
		/*  字符串仍有有结尾0                                                   */
		/*  然后 printf 输出                                                    */
		/************************************************************************/
		regerror(c, &reg, regerrbuf, sizeof(regerrbuf));
		regerrbuf[sizeof(regerrbuf) - 1] = '\0';
		printf("%s:%d %s\n",__FILE__,__LINE__, regerrbuf);
		return -1;
	}
	
	if (0 == groupcnt)
	{
		groupcnt = reg.re_nsub + 1;
	}
	c = rx_search_match_init(_psmatch, groupcnt);
	if (0 != c)
	{
		/** search_match_t 初始化失败,释放前面初始化成功的 regex_t */
		regfree(&reg);
		return c;
	}
	/** 起始匹配的偏移量 */
	size_t offset = 0;
	/************************************************************************/
	/* regexec 不能通过一次调用找到字符串中所有满足匹配条件的字符串位置,    */
	/* 所以需要通过步进偏移的方式循环查找字符串中所有匹配的字符串,          */
	/* 每一次匹配的起始偏移是上一次匹配到的字符串结束偏移                   */
	/************************************************************************/
	do {
		printf("MATCH start %d\n", (int)offset);
		/** 输出缓冲区扩容 */
		regmatch_t* pmatch = rx_search_match_ensure(_psmatch, 1);
		if (NULL == pmatch)
		{
			printf("%s:%d MEMORY ERROR for rx_search_match_ensure\n",__FILE__,__LINE__);
			c = -1;
			break;
		}
		/** 正则表达式匹配的起始地址 */
		const char* p = input + offset;
		/************************************************************************/
		/* regmatch_t 用于记录正则表达匹配的结果,每一个 regmatch_t 记录一个捕获 */
		/* 组(catch group)的在字符串中的起始位置。                              */
		/* 如果调用 regexec 时如果不提供 regmatch_t(nmatch为0,pmatch为NULL),    */
		/* 或者提供的 regmatch_t 数组长小于正则表达式中全部捕获组的数量,        */
		/* regexec 也能正常匹配,只是无法记录匹配的位置                          */
		/* 或不能完全记录所有的匹配结果                                         */
		/************************************************************************/
		c = regexec(&reg, p, _psmatch->groupcnt, pmatch, eflags);
		if (REG_NOMATCH == c)
		{
			/************************************************************************/
			/** 没有找到匹配结束循环                                                */
			/************************************************************************/
			printf("MATCH FINISHED\n");
			break;
		}
		else if (0 == c)
		{
			/** 匹配计数加1 */
			_psmatch->matchcnt++;
			/** 找到匹配,则输出匹配到的所有捕获组(catch group) */
			printf("%d MATCH (%d-%d)\n", (int)_psmatch->matchcnt, pmatch[0].rm_so, pmatch[0].rm_eo);
			for (int i = 0; i < _psmatch->groupcnt; ++i)
			{
				printf("group %d :<<", i);
				print_str(p, pmatch[i].rm_so, pmatch[i].rm_eo);
				printf(">>\n");
			}
			/** (group 0)的结束位置 */
			size_t eo = pmatch[0].rm_eo;
			for (int i = 0; i < _psmatch->groupcnt; ++i)
			{
				/** 偏移量修改为相对于字符串起始位置 */
				pmatch[i].rm_so += (int)offset;
				pmatch[i].rm_eo += (int)offset;
			}
			/************************************************************************/
			/* 使用整体匹配捕获组0(group 0)的结束位置的更新偏移量,                  */
			/* 下一次匹配从当前匹配的结束位置开始                                   */
			/************************************************************************/
			offset += eo;
			continue;
		}
		else
		{
			/************************************************************************/
			/** regexec 调用出错输出错误信息,结束循环                               */
			/************************************************************************/
			regerror(c, &reg, regerrbuf, sizeof(regerrbuf));
			regerrbuf[sizeof(regerrbuf) - 1] = '\0';
			printf("%s\n", regerrbuf);
			c = -1;
			break;
		}
	} while (1);
	printf("%d MATCH FOUND\n", (int)_psmatch->matchcnt);
	/************************************************************************/
	/** regfree 必须与 regcomp 配对使用,否则会发生内存泄露                  */
	/************************************************************************/
	regfree(&reg);
	/** REG_NOMATCH 为正常循环结束标志  */
	if (c != REG_NOMATCH)
	{
		/** 出错时释放 search_match_t 所占内存 */
		rx_search_match_uninit(_psmatch);
		return c;
	}
	return (int)_psmatch->matchcnt;

}

int main() {

	/** 待匹配字符串 */
	const char* inputstr = "hello,welcome to my party";
	regex_t reg;
	/** 正则表达式 */
	const char* pattern = "(we|par)([a-z]+)";
	printf("==rx_serach Test==\n");
	printf("Pattern     :%s\n", pattern);
	printf("Input String:%s\n", inputstr);
	search_match_t _smatch;
	int c = rx_serach(inputstr,pattern, 0, 0, &_smatch);	
	if(c > 0)
	{
		/* 输出 search_match_t 中记录的所有匹配结果 */
		printf("====MATCH RESULT====\n");
		size_t off = 0;
		for (int i = 0; i < c; ++i,off += _smatch.groupcnt)
		{
			printf("MATCH %d\n", i);
			regmatch_t* gm = _smatch.pmatch + off ;
			for (int g = 0; g < _smatch.groupcnt; ++g)
			{
				printf("\tgroup %d <<", g);
				print_str(inputstr, gm[g].rm_so, gm[g].rm_eo);
				printf(">>\n");

			}			
		}
	}
	/************************************************************************/
	/* 调用 rx_serach 之后必须调用 rx_search_match_uninit 释放分配的内存    */
	/* 否则会产生内存泄露                                                   */
	/************************************************************************/
	rx_search_match_uninit(&_smatch);
	return 0;

}

编译示例

gcc/linux

因为linux gcc内置了GNU regex,所以上面的代码在linux下编译很简单:

# 编译 
$ gcc rx_search_test.c 
# 运行测试
$ ./a.out 
==rx_serach Test==
Pattern     :(we|par)([a-z]+)
Input String:hello,welcome to my party
MATCH start 0
1 MATCH (6-13)
group 0 :<<welcome>>
group 1 :<<we>>
group 2 :<<lcome>>
MATCH start 13
2 MATCH (7-12)
group 0 :<<party>>
group 1 :<<par>>
group 2 :<<ty>>
MATCH start 25
MATCH FINISHED
2 MATCH FOUND
====MATCH RESULT====
MATCH 0
	group 0 <<welcome>>
	group 1 <<we>>
	group 2 <<lcome>>
MATCH 1
	group 0 <<party>>
	group 1 <<par>>
	group 2 <<ty>>

MSVC/Windows

因为MSVC没有提供GNU regex库,在windows下编译上面的代码所需要的GNU regex library请参见我另一篇博客
《MSVC下使用gnu regex(正则表达式C语言接口regex.h)》

上面的完整的可编译代码以及GNU regex library for MSVC,我放在了码云仓库:
https://gitee.com/l0km/libgnurx-msvc.git

可以执行如下命令,编译运行 rx_search_test.c

# 需要在VS2015 开发人员提示(CMD)下执行,否则找不到nmake命令
J:>git clone https://gitee.com/l0km/libgnurx-msvc.git
J:>cd libgnurx-msvc
J:\libgnurx-msvc>nmake /f NMakefile test3

Microsoft (R) 程序维护实用工具 14.00.24210.0 版
版权所有 (C) Microsoft Corporation。  保留所有权利。

        cl.exe /D WIN32 /D _WINDOWS /I . /MD /wd4819 rx_search_test.c regex.lib
用于 x64 的 Microsoft (R) C/C++ 优化编译器 19.00.24215.1 版
版权所有(C) Microsoft Corporation。保留所有权利。

rx_search_test.c
Microsoft (R) Incremental Linker Version 14.00.24215.1
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:rx_search_test.exe
rx_search_test.obj
regex.lib
        rx_search_test.exe
==rx_serach Test==
Pattern     :(we|par)([a-z]+)
Input String:hello,welcome to my party
MATCH start 0
1 MATCH (6-13)
group 0 :<<welcome>>
group 1 :<<we>>
group 2 :<<lcome>>
MATCH start 13
2 MATCH (7-12)
group 0 :<<party>>
group 1 :<<par>>
group 2 :<<ty>>
MATCH start 25
MATCH FINISHED
2 MATCH FOUND
====MATCH RESULT====
MATCH 0
        group 0 <<welcome>>
        group 1 <<we>>
        group 2 <<lcome>>
MATCH 1
        group 0 <<party>>
        group 1 <<par>>
        group 2 <<ty>>

J:\libgnurx-msvc>
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,要提取含有ftp的链接,且文件类型是gz或者xz的文件名,可以使用如下正则表达式: ``` ftp://[^\s]*\.(gz|xz) ``` 这个正则表达式的意思是:匹配以ftp://开头,后面跟着任意非空白字符,直到遇到.gz或者.xz的文件名。其中,[^\s]*表示匹配任意非空白字符,直到遇到.gz或者.xz。 利用正则表达式re模块中的函数将匹配的内容输出,可以使用Python中的re模块实现。示例代码如下: ```python import re s = """ftp://ftp.astrom.com/pub/file/file-5.14.tar.gz ftp://ftp.gmplib.org/pub/gmp-5.1.0/gmp-5.1.00tar.xz ftp://ftp.vim,org/pub/vim/unix/vim-7.3.tar.ba2 http://anduin.linuxfromscratch.org/sources/LFS/lfs-packages/conglomeration//iana-etc/iana-etc-2.30.tar.bz2 http://anduin.linuxfromscratch.org/sources/other/udev-lfs-205-1.tar.bz2 http://download.savannah.gnu.org/releases/libpipeline/libpipeline-1.2.4.tar.gz http://download.savannah.gnu.org/releases/man-db/man-db-2.6.5.tar,xz http://download.savannah.gnu.org/releases/sysvinit/sysvinit-2.88dsf.tar.bz2 http://ftp.altlinux.org/pub/people/legion/kbd-1.15.5.tar.gz http://mirror.hust.edu.cn/gnu/antoconf/autoconf-2.69.tar.gz http://mirror.hust.edu.cn/gnu/antomake/automake-2.69.tar.gz""" pattern = r"ftp://[^\s]*\.(gz|xz)" result = re.findall(pattern, s) print(result) ``` 运行结果为: ``` ['ftp://ftp.astrom.com/pub/file/file-5.14.tar.gz', 'ftp://ftp.gmplib.org/pub/gmp-5.1.0/gmp-5.1.00tar.xz'] ``` 可以看到,只有两个符合条件的链接被提取出来了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值