前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C: GNU regex library (regex.h)正则表达式调用示例

C: GNU regex library (regex.h)正则表达式调用示例

作者头像
10km
发布2021-11-15 16:39:26
8570
发布2021-11-15 16:39:26
举报
文章被收录于专栏:10km的专栏10km的专栏

GNU regex是GNU提供的跨平台的POSIX 正则表达式库(C语言)。 我也是最近才接触这个相对于C++/Java实现来说非常简陋,勉强够用的正则表达式库。 不算GNU提供的扩展函数,POSIX标准的regex库总共就4个函数regcomp,regerror,regexec,regfree, 以下以完整源码的方式调用以上函数完成对GNU regex library的基本测试。

gnuregex_test.c

详细解释参见源码中的注释

代码语言:javascript
复制
/************************************************************************/
/*  gnuregex_test.c                                                     */
/*  GNU Regex 测试                                                      */
/*  测试 regcomp,regerror,regexec,regfree 函数的使用方式                */
/*  author guyadong                                                     */
/************************************************************************/
#include <stdio.h>
#include <regex.h>

/** 输出字符串中指定范围的字符到控制台 */
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]);
		}
	}
}

int main() {

	/** 待匹配字符串 */
	const char* inputstr = "hello,welcome to my party";
	/** regex 错误输出缓冲区 */
	char regerrbuf[256];
	regex_t reg;
	/** 正则表达式 */
	const char* pattern = "(we|par)([a-z]+)";
	printf("==GNU Regex Test==\n");
	printf("Pattern     :%s\n", pattern);
	printf("Input String:%s\n", inputstr);
	/************************************************************************/
	/* 编译正则表达式,编译成功的 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\n", regerrbuf);
		return -1;
	}
	/************************************************************************/
	/* 记录匹配位置的 regmatch_t 数组                                       */
	/* 上面的正则表达有 2 个捕获组,加上默认组(group 0),                     */
	/* 为了记录所有捕获组位置,所以这里需要长度为 3 的 regmatch_t 数组       */
	/************************************************************************/
	const size_t matchsz = 3;
	regmatch_t pmatch[3];
	/** 起始匹配的偏移量 */
	size_t offset = 0;
	/** 捕获计数         */
	int matchcount = 0;
	/************************************************************************/
	/* regexec 不能通过一次调用找到字符串中所有满足匹配条件的字符串位置,    */
	/* 所以需要通过步进偏移的方式循环查找字符串中所有匹配的字符串,          */
	/* 每一次匹配的起始偏移是上一次匹配到的字符串结束偏移                   */
	/************************************************************************/
	do {
		printf("Search start %d\n",(int)offset);
		/** 正则表达式匹配的起始地址 */
		const char* p = inputstr + offset;
		/************************************************************************/
		/* regmatch_t 用于记录正则表达匹配的结果,每一个 regmatch_t 记录一个捕获 */
		/* 组(catch group)的在字符串中的起始位置。                              */
		/* 如果调用 regexec 时如果不提供 regmatch_t(nmatch为0,pmatch为NULL),    */
		/* 或者提供的 regmatch_t 数组长小于正则表达式中全部捕获组的数量,        */
		/* regexec 也能正常匹配,只是无法记录匹配的位置                          */
		/* 或不能完全记录所有的匹配结果                                         */
		/************************************************************************/
		c = regexec(&reg, p, matchsz, pmatch, 0);
		if (REG_NOMATCH == c)
		{
			/** 没有找到匹配结束循环 */
			printf("MATCH FINISHED\n");
			break;
		}
		else if (0 == c)
		{
			/** 找到匹配,则输出匹配到的所有捕获组(catch group) */
			printf("%d MATCH (%d-%d)\n", ++matchcount, pmatch[0].rm_so, pmatch[0].rm_eo);
			for (int i = 0; i < matchsz; ++i)
			{
				printf("group %d :<<", i);
				print_str(p, pmatch[i].rm_so, pmatch[i].rm_eo);
				printf(">>\n");
			}
			/************************************************************************/
			/* 使用整体匹配捕获组0(group 0)的结束位置的更新偏移量,                  */
			/* 下一次匹配从当前匹配的结束位置开始                                   */
			/************************************************************************/
			offset += pmatch[0].rm_eo;
			continue;
		}
		else
		{
			/************************************************************************/
			/** regexec 调用出错输出错误信息,结束循环                               */
			/************************************************************************/
			regerror(c, &reg, regerrbuf, sizeof(regerrbuf));
			regerrbuf[sizeof(regerrbuf) - 1] = '\0';
			printf("%s\n", regerrbuf);
			break;
		}
	} while (1);
	printf("%d MATCH FOUND\n", matchcount);
	/************************************************************************/
	/** regfree 必须与 regcomp 配对使用,否则会发生内存泄露                  */
	/************************************************************************/
	regfree(&reg);
	return 0;

}

运行输出:

代码语言:javascript
复制
>gnuregex_test.exe
==GNU Regex Test==
Pattern     :(we|par)([a-z]+)
Input String:hello,welcome to my party
Search start 0
1 MATCH (6-13)
group 0 :<<welcome>>
group 1 :<<we>>
group 2 :<<lcome>>
Search start 13
2 MATCH (7-12)
group 0 :<<party>>
group 1 :<<par>>
group 2 :<<ty>>
Search start 25
MATCH FINISHED
2 MATCH FOUND

说明

  1. 调用regcomp时对regex_t对象会有分配内存,所以用完的regex_t对象一定要调用regfree释放,否则会发生内存泄露。
  2. 如果只是想判断字符串是否匹配正则表达式,而不关心匹配的位置,在执行regexec可以不需要填保存匹配结果的regmatch_t相关参数,即第3,4个参数(__nmatch,__pmatch)填0.
  3. 如果字符串有多个匹配,regexec 不能通过一次调用找到字符串中所有满足匹配条件的字符串位置,所以需要通过步进偏移的方式循环查找字符串中所有匹配的字符串,每一次匹配的起始偏移是上一次匹配到的字符串结束偏移

libgnurx-msvc

以上代码在MSVC和gcc编译运行通过。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-11-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • gnuregex_test.c
  • 说明
  • libgnurx-msvc
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档