GNU/Linux有两套库可用于正则表达式编程:POSIX库和PCRE库。前者不需要单独安装,一般需求还是能满足的,速度稍慢些。后者是久负盛名的Perl正则表达式库,功能强大,匹配速度快,不过可能需要单独安装。
本文介绍如何使用POSIX库。
#i nclude <stdio.h>
#i nclude <sys/types.h>
#i nclude <regex.h>
char *get_regerror (int errcode, regex_t *compiled)
{
size_t length = regerror (errcode, compiled, NULL, 0);
char *buffer = malloc(length);
if (!buffer) return NULL;
(void) regerror (errcode, compiled, buffer, length);
return buffer;
}
int regtest(const char*pattern, const char* string)
{
regex_t reg;
regmatch_t *subexprs = NULL;
int ret;
int i;
if (0 != (ret=regcomp(?, pattern, REG_EXTENDED))) {
char *buffer = get_regerror(ret, ?);
if (buffer) {
fprintf(stderr, "regcomp:[%d]%s\n", ret, buffer);
free(buffer);
}
return -1;
}
subexprs = malloc((reg.re_nsub+1)*sizeof(regmatch_t));
if (!subexprs) {
fprintf(stderr, "error malloc subexprs\n");
regfree(?);
return -1;
}
if (0 != (ret=regexec(?, string, reg.re_nsub+1, subexprs, 0))) {
char *buffer = get_regerror(ret, ?);
if (buffer) {
fprintf(stderr, "regexec:[%d]%s\n", ret, buffer);
free(buffer);
}
regfree(?);
return -1;
}
for (i = 0; i <= reg.re_nsub; i++) {
printf("[%d]:", i);
if (subexprs[i].rm_so == subexprs[i].rm_eo) {
printf("[EMPTY SUBEXPR]\n");
}
else if (subexprs[i].rm_so == -1 ||
subexprs[i].rm_eo == -1) {
printf("[NO SUBEXPR]\n");
}
else {
fwrite(string+subexprs[i].rm_so, 1,
subexprs[i].rm_eo-subexprs[i].rm_so, stdout);
printf("\n");
}
}
regfree(?);
if (subexprs) free(subexprs);
return 0;
}
int main(int argc, char *argv[])
{
if (argc != 3) {
fprintf(stderr, "Usage: regtest pattern string\n");
return -1;
}
fprintf(stderr, "pattern:%s\n", argv[1]);
fprintf(stderr, "string:%s\n", argv[2]);
return regtest(argv[1], argv[2]);
}
在字符串匹配之前,我们必须先编译匹配模式,这是通过regcomp实现的。这个函数的原型如下:
int regcomp (regex_t *compiled, const char *pattern, int cflags)
参数compiled只有一个成员是我们需要关注的,那就是re_nsub,代表编译后的子表达式数目,由于我们还需要保存整个匹配到的模式,所以最终匹配的条目数是re_nsub加1。cflags用来修饰匹配模式,可取值如下:
REG_EXTENDED 启用POSIX正则库扩展,关于该扩展的详细信息可参考POSIX规范
REG_ICASE 忽略大小写
REG_NOSUB 不要存储子表达式
REG_NEWLINE 把换行符作为多行的分隔符,这样'$'可匹配每一行的行尾,'^'匹配每一行的行首,'.'不匹配换行符,[^...]不匹配新行
编译完模式后我们从内存中分配子表达式存储空间,然后调用regexec对串进行匹配,该函数原型如下:
int regexec (regex_t *compiled, char *string, size_t nmatch, regmatch_t matchptr [], int eflags)
nmatch指明matchptr数组的数目,该数目是compiled->re_nsub+1,也可以让nmatch为0,matchptr为NULL,表示不要保存子表达式。eflags通常为0。
匹配结束后,匹配到的子表达式在串中的偏移保存在regmatch_t结构中,该结构有两个成员:
rm_so 子表达式的起始偏移
rm_eo 子表达式的结束偏移
这是一个开区间,实际的子表达式在[rm_so,rm_eo)里。
如果没有匹配的子表达式,比如"f(o*)"匹配"fum",实际匹配到的只有"f",这时rm_so和rm_eo相等,都为1。如果整个模式在没有子表示式的情况下也能匹配,这时rm_so和rm_eo为-1,比如"ba(na)*"匹配"ba"。
void regfree(regex_t *preg);
函数regfree()不会返回任何结果,它仅接收一个指向regex_t数据类型的指针,这是之前调用regcomp()函数所得到的编译结果。
如 果在程序中针对同一个regex_t结构调用了多次regcomp()函数,POSIX标准并没有规定是否每次都必须调用regfree()函数进行释 放,但建议每次调用regcomp()函数对正则表达式进行编译后都调用一次regfree()函数,以尽早释放占用的存储空间。
报告错误信息
如果调用函数regcomp()或regexec()得到的是一个非0的返回值,则表明在对正则表达式的处理过程中出现了某种错误,此时可以通过调用函数regerror()得到详细的错误信息。
Param
参数errcode 是来自函数regcomp()或regexec()的错误代码,
参数preg 是由函数regcomp()得到的编译结果,
其目的是把格式化消息所必须的上下文提供给regerror()函数。
参数errbuf_size指明的最大字节数,









