C语言正则表达式

在很多人看来,正则表达式看上去古怪且复杂,因此往往不想去触及或使用。如果我们抛开这种“畏难”心理,在经过循序渐进地学习之后,就会发现这些复杂的表达式其实写起来还是相当简单的。一旦它被你所“驯服”,就可利用正则表达式把原需数小时辛苦且易错的文本处理工作压缩在几分钟(甚至几秒钟)内完成。

 

正则表达式定义
正则表达式(regular expression)是Linux系统中一种非常重要的字符串搜索模式,是一组规则字符的集合。这些规则字符能够组成我们所需要的搜索规则,效率高、功能强,可以极大地简化处理字符串时的复杂度。在很多Linux工具(sed、grep、find等)和脚本语言(awk、perl等)中都有着重要的地位。当我们在编写字符串相关的应用程序时,掌握正则表达式会起到事半功倍的效果。

C中的正则表达式
标准C和C++都不支持正则表达式,但是千万不要以为正则表达式就只是Perl、Python、Bash等脚本语言的专利,作为C语言程序员,用户同样可以在自己的程序中运用正则表达式,只是需要一些函数库辅助C/C++程序员来完成这一功能。许多Linux发行版本都带有POSIX函数库,下面我将以POSIX函数库中的Regex系列函数来说明在Linux c下如何使用正则表达式。
首先要用Regcomp()函数对它进行编译,将其转化为Regex_t结构。因为一个正则表达式需要编译成一个特定的数据结构才能被后续的函数使用。Regcomp()函数的原型是:
int Regcomp(regex_t *preg, const char *regex, int cflags)
参数preg指向一个声明为regex_t的数据结构,用来保存编译结果。参数regex为要编译的正则表达式字符串。参数cflags是编译开关,编译开关可以控制规则生成的特性,如REG_EXTEND代表使用扩展正则表达式模式;REG_ICASE表示对规则中字符串不区分大小写;REG_NOSUB只检查是否有符合规则的子串。
下面匹配正则表达式,一旦用Regcomp()函数成功地编译了正则表达式,接下来就可调用regexec()函数完成模式匹配。Regexec()函数的原型:
int regexec(const regex_t *preg, const char *string, size_t nmatch,regmatch_t pmatch[], int eflags)
函数用于在字符串(参数string)中匹配正则表达式(参数preg)。而参数nmatch和pmatch则用于把匹配结果返回给调用程序。在调用函数egexec()进行模式匹配的过程中,可能在字符串string中会有多处与给定的正则表达式相匹配。参数pmatch用来保存这些匹配位置。参数nmatch则告诉函数regexec()最多可以把多少个匹配结果填充到pmatch数组中。
typedef struct {
regoff_t rm_so;
regoff_t rm_eo;
} regmatch_t; 
其中rm_so表示满足规则的子串在string中的起始偏移量,rm_eo表示满足规则的子串在string中的后续偏移量。当regexec成功返回时,从pmatch[0].rm_so到pmatch[0].rm_eo是第一个匹配的字符串。最后一个参数eflags决定了匹配的特性,当需要匹配的string非常大的时候可以通过eflags来表示是否是第一行(REG_NOTBOL),或最后一行(REG_NOTEOL)。
还有一个函数是用来获取错误信息的,size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)。参数errcode是来自函数Regcomp()或regexec()的错误代码,而参数preg则是由函数Regcomp()得到的编译结果,其目的是把格式化消息所必须的上下文提供给regerror()函数。在执行函数regerror()时,将按照参数errbuf_size指明的最大字节数。在errbuf缓冲区中填入格式化后的错误信息,同时返回错误信息的长度。
最后释放正则表达式。无论什么时候,当不再需要已经编译过的正则表达式时,都应该调用函数regfree()将其释放,以免产生内存泄漏。void regfree(regex_t *preg); 函数regfree()不会返回任何结果,它仅接收一个指向regex_t数据类型的指针,这是之前调用Regcomp()函数所得到的编译结果。

实例说明
下面介绍如何在Linux C中正确使用正则表达式,以查找有关字符串并打印出来为例:
#include <stdio.h>
#include <sys/types.h>
#include <regez.h>

in chk_line(int lineno, regex_t *reg,char *line)
{
int rtn,i,len;
regmatch_t pmatch;
char *url,*pbuf;

fprintf(stderr,"%4d",lineno);
rtn = regexec(reg,line,1,&pmatch,0);
pbuf = line;
while(rtn == 0)
{
len = pmatch.rm_eo - pmatch.rm_so;
url = (char*)malloc((len+1)*sizeof(char));
memset(url,0,(len+1)*sizeof(char));
memcpy(url,&pbuf[pmatch.rm_so].len);
fprintf(stderr,"%s",url);
free(url);
pbuf += pmatch.rm_eo;
rtn = regexec(reg,pbuf,1,&pmatch,REG_NOTBOL);
}
fprintf(stderr,"/n");
return 0;
}
int chk_file(const char *filename)
{
FILE *fp;
char *pattern = "^(hisencyber)(.com|.com.cn)";
char buf[1024],line[1024];
int rtn,lineno,flag;

fp = fopen(filename,"r");
if(fp == NULL)
{
fprintf(stderr,"OPen file failed/n",filename);
return -1;
}
rtn = Regcomp(®,patten,REG_ICASE|REG_EXTENDED);
if(rtn)
{
fprintf(stderr,"compile failed./n");
fclose(fp);
return -1;
}
lineno = 1;
memset(line,0,sizeof(line));
while(fgets(line,sizeof(line),fp)!= NULL)
{
chk_line(lineno++,®,line);
}
fclose(fp);
regefree(®);
return 0;
}
int main (int argc,char *argv[])
{
int rtn;
if(argc != 2)
{
fprintf(stderr,"Usage:chkfileurl <file> /n ");
return 1;
}
rtn = chk_file(argv[1]);
return rtn;
}

正则表达式示例表
字 符 意 义 示 例
* 任意长度的字符串。 a* 表示: 空字符串、aaaa、a…
? 长度为0或者1的字符串。 a? 表示: 空字符串和a。
+ 长度为一个或者多个的字符串。 a+表示:a、aa、aaaaaa…
. 任意字符。 a. 表示:a后跟任意字符。
{} 代表上一规则重复数目、
{1,1,s}包含一组匹配花括号,里面有两个数字和一个字符,表示在指定次数范围内找到字符。 a{3}表示:三个a、
a{1,3}表示:一个到三个a、
a{3,} 表示:大于等于三个a、
{3,7,a}表示在3到7次重复范围内匹配字符a。
[] 集合,代表方括号中任意一个字符。 [ab] 表示:a或者b都可以、
[a-z] 表示:从a到z的字符。
() 组,代表一组字符。 (ab){2}表示:abab。
a/b 同时满足。 a/b表示:字符串a后跟字符串b才能满足要求。
a|b 并列,代表符合a或者符合b都可以 a|b表示: 字符串a或者字符串b都满足要求。
^ 如果放在开头表示代表该规则必须在字符串的开头,其他位置代表字符本身。
如果放在[]中的开头表示对该集合取反,其他位置代表字符本身。 ^a表示:a必须在字符串的开头、
[^a]表示:除了a以外的其他字符。
$ 如果放在最后表示该规则必须放在最后,其他位置代表字符本身。 a$表示:a必须在字符串最后。
/:s 正则表达式用 /:s 表示空格。 a/:sb 匹配 a b。
/:a 正则表达式用 /:a 表示字符与数字。 a/:a 匹配 ab、a6 等。
/:c 正则表达式用 /:c 仅表示字符。 a/:c 匹配 ac等,不匹配a1等。
/:p 正则表达式用 /:p 表示可打印字符。 
/:D 正则表达式用 /:d 仅表示数字。 a/:c 匹配 a1等,不匹配ac等。
/:x00 正则表达式用 /:x00 表示ASCII字符。 
/:r 正则表达式用 /:r 表示回车。 
/:N 正则表达式用 /:d 表示换行。

本文重点在于阐述如何在Linux C中利用正则表达式来简化字符串处理,另外Linux中正则表达式内部定义了诸多内部规则来方便开发人员使用,具体含义可以查看 man regex,相信熟悉它对你的工作会有非常大的帮助!

<think>好的,我现在需要帮助用户了解如何在C语言中使用正则表达式,包括方法和示例。首先,我需要回忆C语言中处理正则表达式的相关函数和步骤。根据用户提供的引用内容,引用了regcomp、regexec、regfree和regerror这几个函数,处理步骤分为三步:编译正则表达式、匹配字符串、释放资源。 首先,用户的问题是如何在C语言中使用正则表达式,所以需要分步骤说明,并给出示例代码。根据引用[1]和引用[2],处理正则表达式主要涉及这三个函数。因此,我应该先列出这三个步骤,并解释每个步骤的作用。 接下来,我需要编写示例代码。引用[3]提到了示例代码,但用户提供的引用中没有具体的代码。不过,根据标准C库的regex.h用法,可以构造一个简单的例子。例如,编译正则表达式,然后进行匹配,最后释放资源。需要注意regcomp的参数,比如REG_EXTENDED和REG_ICASE等标志位的使用,这在引用[2]中提到过。同时,处理匹配结果时,regexec返回不同的值,如0表示成功,REG_NOMATCH表示不匹配,其他错误则需要用regerror获取错误信息,这在引用[5]中提到了错误处理的情况。 然后,用户可能遇到的问题包括如何编写正则表达式模式,如何处理匹配结果中的多个子表达式,以及错误处理。例如,在示例中,使用regmatch_t结构体来获取匹配的位置,这在引用[3]或引用[4]中可能有所提及。需要解释pmatch数组的作用,以及如何访问匹配到的子字符串。 另外,需要注意不同平台和库的差异,比如Windows环境下可能需要使用不同的库,如PCRE,但用户的问题可能集中在标准regex.h库的使用,所以应主要基于POSIX正则表达式函数。引用[3]提到了PCRE,但用户提供的示例代码可能更倾向于标准库,因此需要明确说明使用的是regex.h中的函数。 还需要考虑编译时的链接问题,比如在Linux下需要链接特定的库吗?一般情况下,regex.h是标准C库的一部分,所以可能不需要额外的链接选项,但可能需要检查环境支持。 然后,生成相关问题。根据用户提供的示例,问题应该围绕C语言正则表达式的使用,可能的扩展问题包括高级匹配技巧、错误处理、性能优化、不同库的比较,以及实际应用案例。例如,引用[3]提到PCRE,可以生成相关问题比较regex和PCRE的区别。 在回答过程中,要确保LaTeX格式的正确应用,行内公式用$...$,独立公式用$$...$$,但在这个问题中可能涉及较少的数学公式,更多是代码示例。但如果有正则表达式的模式,可能需要用行内代码块或LaTeX的转义字符,比如用$[A-Za-z]+$表示匹配字母的正则表达式。 最后,需要检查引用是否正确添加,确保每个引用的末尾都有对应的标识,如[^1]、[^2]等,并且引用内容与用户提供的引用一致。例如,在步骤中提到regcomp函数时,可以引用[2],在错误处理时引用[5]。 总结回答的结构应该是: 1. 引入:说明C语言中使用正则表达式的步骤和函数。 2. 分步骤说明:编译、匹配、释放资源,每个步骤详细解释。 3. 示例代码:展示一个完整的例子,并解释关键部分。 4. 注意事项:常见问题、错误处理、子表达式匹配等。 5. 相关问题:生成几个相关问题,帮助用户进一步学习。 现在需要确保示例代码正确,没有语法错误,并且注释清晰。例如,在代码中处理匹配结果时,检查regexec的返回值,并输出相应的信息。同时,演示如何获取匹配的子字符串的位置,如pmatch[0].rm_so和rm_eo。 可能需要注意的问题包括:regcomp的错误码处理,如编译失败时的处理;regexec的匹配标志,如REG_NOTBOL等,但示例中可以简化处理,不涉及复杂标志。此外,确保在代码结束后调用regfree释放内存,避免内存泄漏。 最后,生成的相关问题需要覆盖用户可能感兴趣的扩展方向,如高级用法、不同库的选择、性能优化等。</think>在C语言中使用正则表达式主要通过`regex.h`库中的函数实现,具体步骤如下: --- ### **C语言正则表达式使用步骤** 1. **编译正则表达式** 使用`regcomp()`将字符串形式的正则表达式编译为可执行格式[^2]: ```c int regcomp(regex_t *preg, const char *regex, int cflags); ``` - `preg`:指向`regex_t`结构体的指针,用于存储编译后的正则表达式。 - `regex`:字符串形式的正则表达式,例如`^[A-Za-z]+$`(匹配纯字母字符串)。 - `cflags`:编译标志,如`REG_EXTENDED`(启用扩展语法)或`REG_ICASE`(忽略大小写)。 2. **执行匹配** 使用`regexec()`对目标字符串进行匹配[^1]: ```c int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags); ``` - `string`:待匹配的字符串。 - `pmatch`:存储匹配结果的数组,`regmatch_t`结构体包含匹配的起始和结束位置。 - 返回值:`0`表示匹配成功,`REG_NOMATCH`表示不匹配,其他值为错误码。 3. **释放资源** 使用`regfree()`释放编译后的正则表达式占用的内存[^1]。 --- ### **示例代码** ```c #include <stdio.h> #include <regex.h> int main() { regex_t regex; int rc; char *pattern = "^[A-Za-z0-9_]+$"; // 匹配字母、数字和下划线 char *test_str = "Hello_123"; // 1. 编译正则表达式 rc = regcomp(&regex, pattern, REG_EXTENDED); if (rc != 0) { char error_msg[100]; regerror(rc, &regex, error_msg, sizeof(error_msg)); printf("编译错误: %s\n", error_msg); return 1; } // 2. 执行匹配 rc = regexec(&regex, test_str, 0, NULL, 0); if (rc == 0) { printf("字符串匹配成功\n"); } else if (rc == REG_NOMATCH) { printf("字符串不匹配\n"); } else { regerror(rc, &regex, error_msg, sizeof(error_msg)); printf("匹配错误: %s\n", error_msg); } // 3. 释放资源 regfree(&regex); return 0; } ``` --- ### **关键注意事项** 1. **错误处理** 若`regcomp`或`regexec`返回非零值,需用`regerror()`获取错误信息[^5]。 2. **子表达式匹配** 若需提取匹配的子字符串,可定义`regmatch_t pmatch[n]`数组,并在`regexec`中指定`nmatch`参数: ```c regmatch_t pmatch[1]; rc = regexec(&regex, test_str, 1, pmatch, 0); if (rc == 0) { printf("匹配位置: %d-%d\n", pmatch[0].rm_so, pmatch[0].rm_eo); } ``` 3. **正则表达式语法** 默认使用基本语法,若需支持扩展语法(如`|`或`+`),需在`regcomp`中设置`REG_EXTENDED`标志。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值