C语言正则表达式

1.int regcomp (regex_t *compiled, const char *pattern, int cflags)

这个函数把指定的规则表达式pattern编译成一种特定的数据格式compiled,这样可以使匹配更有效。函数regexec 会使用这个数据在目标文本串中进行模式匹配。执行成功返回0。

regex_t 是一个结构体数据类型,用来存放编译后的规则表达式,它的成员re_nsub 用来存储规则表达式中的子规则表达式的个数,子规则表达式就是用圆括号包起来的部分表达式。

pattern 是指向我们写好的规则表达式的指针。
cflags 有如下4个值或者是它们或运算(|)后的值:
REG_EXTENDED 以功能更加强大的扩展规则表达式的方式进行匹配。
REG_ICASE 匹配字母时忽略大小写。
REG_NOSUB 不用存储匹配后的结果。
REG_NEWLINE 识别换行符,这样'$'就可以从行尾开始匹配,'^'就可以从行的开头开始匹配。

2. int regexec (regex_t *compiled, char *string, size_t nmatch, regmatch_t matchptr [], int eflags)

当我们编译好规则表达式后,就可以用regexec 匹配我们的目标文本串了,如果在编译规则表达式的时候没有指定cflags的参数为REG_NEWLINE,则默认情况下是忽略换行符的,也就是把整个文本串当作一个字符串处理。执行成功返回0。

regmatch_t 是一个结构体数据类型,成员rm_so 存放匹配文本串在目标串中的开始位置,rm_eo 存放结束位置。通常我们以数组的形式定义一组这样的结构。因为往往我们的规则表达式中还包含子规则表达式。数组0单元存放主规则表达式位置,后边的单元依次存放子规则表达式位置。

compiled 是已经用regcomp函数编译好的规则表达式。
string 是目标文本串。
nmatch 是regmatch_t结构体数组的长度。
matchptr regmatch_t类型的结构体数组,存放匹配文本串的位置信息。
eflags 有两个值
REG_NOTBOL 按我的理解是如果指定了这个值,那么'^'就不会从我们的目标串开始匹配。总之我到现在还不是很明白这个参数的意义, 原文如下:
If this bit is set, then the beginning-of-line operator doesn't match the beginning of the string (presumably because it's not the beginning of a line).If not set, then the beginning-of-line operator does match the beginning of the string.
REG_NOTEOL 和上边那个作用差不多,不过这个指定结束end of line。

3. void regfree (regex_t *compiled)

当我们使用完编译好的规则表达式后,或者要重新编译其他规则表达式的时候,我们可以用这个函数清空compiled指向的regex_t结构体的内容,请记住,如果是重新编译的话,一定要先清空regex_t结构体。

4. size_t regerror (int errcode, regex_t *compiled, char *buffer, size_t length)

当执行regcomp 或者regexec 产生错误的时候,就可以调用这个函数而返回一个包含错误信息的字符串。

errcode 是由regcomp 和 regexec 函数返回的错误代号。
compiled 是已经用regcomp函数编译好的规则表达式,这个值可以为NULL。
buffer 指向用来存放错误信息的字符串的内存空间。
length 指明buffer的长度,如果这个错误信息的长度大于这个值,则regerror 函数会自动截断超出的字符串,但他仍然会返回完整的字符串的长度。所以我们可以用如下的方法先得到错误字符串的长度。
size_t length = regerror (errcode, compiled, NULL, 0);


----------------------------------------------------------------------
如果用户熟悉Linux下的sed、awk、grep或vi,那么对正则表达式这一概念肯定不会陌生。由于它可以极大地简化处理字符串时的复杂度,因此现在已经在许多Linux实用工具中得到了应用。千万不要以为正则表达式只是Perl、Python、Bash等脚本语言的专利,作为C语言程序员,用户同样可以在自己的程序中运用正则表达式。

标准的C和C++都不支持正则表达式,但有一些函数库可以辅助C/C++程序员完成这一功能,其中最著名的当数Philip Hazel的Perl-Compatible Regular Expression库,许多Linux发行版本都带有这个函数库。

编译正则表达式

为了提高效率,在将一个字符串与正则表达式进行比较之前,首先要用regcomp()函数对它进行编译,将其转化为regex_t结构:


int regcomp(regex_t *preg, const char *regex,
int cflags);


参数regex是一个字符串,它代表将要被编译的正则表达式;参数preg指向一个声明为regex_t的数据结构,用来保存编译结果;参数cflags决定了正则表达式该如何被处理的细节。

如果函数regcomp()执行成功,并且编译结果被正确填充到preg中后,函数将返回0,任何其它的返回结果都代表有某种错误产生。

匹配正则表达式 feedom.net

一旦用regcomp()函数成功地编译了正则表达式,接下来就可以调用regexec()函数完成模式匹配:


int regexec(const regex_t *preg,
const char *string, size_t nmatch,
regmatch_t pmatch[], int eflags);
typedef struct {
regoff_t rm_so;
regoff_t rm_eo;
} regmatch_t;


参数preg指向编译后的正则表达式,参数string是将要进行匹配的字符串,而参数nmatch和pmatch则用于把匹配结果返回给调用程序,最后一个参数eflags决定了匹配的细节。

在调用函数regexec()进行模式匹配的过程中,可能在字符串string中会有多处与给定的正则表达式相匹配,参数pmatch就是用来保存这些匹配位置的,而参数nmatch则告诉函数regexec()最多可以把多少个匹配结果填充到pmatch数组中。当regexec()函数成功返回时,从string+pmatch[0].rm_so到string+pmatch[0].rm_eo是第一个匹配的字符串,而从string+pmatch[1].rm_so到string+pmatch[1].rm_eo,则是第二个匹配的字符串,依此类推。

释放正则表达式

无论什么时候,当不再需要已经编译过的正则表达式时,都应该调用函数regfree()将其释放,以免产生内存泄漏。

网管网bitsCN.com
void regfree(regex_t *preg);


函数regfree()不会返回任何结果,它仅接收一个指向regex_t数据类型的指针,这是之前调用regcomp()函数所得到的编译结果。

如果在程序中针对同一个regex_t结构调用了多次regcomp()函数,POSIX标准并没有规定是否每次都必须调用regfree()函数进行释放,但建议每次调用regcomp()函数对正则表达式进行编译后都调用一次regfree()函数,以尽早释放占用的存储空间。

报告错误信息

如果调用函数regcomp()或regexec()得到的是一个非0的返回值,则表明在对正则表达式的处理过程中出现了某种错误,此时可以通过调用函数regerror()得到详细的错误信息。


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缓冲区中填入格式化后的错误信息,同时返回错误信息的长度。

应用正则表达式
中国网管联盟www、bitsCN、com


最后给出一个具体的实例,介绍如何在C语言程序中处理正则表达式。


#include <stdio.h>
#include <sys/types.h>
#include <regex.h>

/* 取子串的函数 */
static char* substr(const char*str,
unsigned start, unsigned end)
{
unsigned n = end - start;
static char stbuf[256];
strncpy(stbuf, str + start, n);
stbuf[n] = 0;
return stbuf;
}
/* 主程序 */
int main(int argc, char** argv)
{
char * pattern;
int x, z, lno = 0, cflags = 0;
char ebuf[128], lbuf[256];
regex_t reg;
regmatch_t pm[10];
const size_t nmatch = 10;
/* 编译正则表达式*/
pattern = argv[1];
z = regcomp(?, pattern, cflags);
if (z != 0){
regerror(z, ?, ebuf, sizeof(ebuf));
fprintf(stderr, "%s: pattern '%s' \n",
ebuf, pattern);
return 1;
}
/* 逐行处理输入的数据 */
while(fgets(lbuf, sizeof(lbuf), stdin))
{
++lno;
if ((z = strlen(lbuf)) > 0 && lbuf[z-1]
网管联盟www.bitsCN.com


== '\n')
lbuf[z - 1] = 0;
/* 对每一行应用正则表达式进行匹配 */
z = regexec(?, lbuf, nmatch, pm, 0);
if (z == REG_NOMATCH) continue;
else if (z != 0) {
regerror(z, ?, ebuf, sizeof(ebuf));
fprintf(stderr, "%s: regcom('%s')\n",
ebuf, lbuf);
return 2;
}
/* 输出处理结果 */
for (x = 0; x < nmatch && pm[x].rm_so != -1; ++ x)
{
if (!x) printf("%04d: %s\n", lno, lbuf);
printf(" $%d='%s'\n", x, substr(lbuf, pm[x].rm_so,
pm[x].rm_eo));
}
}
/* 释放正则表达式 */
regfree(?);
return 0;
}


 上述程序负责从命令行获取正则表达式,然后将其运用于从标准输入得到的每行数据,并打印出匹配结果。执行下面的命令可以编译并执行该程序:


# gcc regexp.c -o regexp
# ./regexp 'regex[a-z]*' < regexp.c
0003: #include <regex.h>
$0='regex'
0027: regex_t reg;
$0='regex'
0054: z = regexec(?, lbuf, nmatch, pm, 0);
$0='regexec'


54com.cn


小结

对那些需要进行复杂数据处理的程序来说,正则表达式无疑是一个非常有用的工具。本文重点在于阐述如何在C语言中利用正则表达式来简化字符串处理,以便在数据处理方面能够获得与Perl语言类
似的灵活性。
【转自www.bitsCN.com】
<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`标志。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值