使用POSIX正则库匹配一行中多个结果

正则匹配与正则表达式是什么东西我就不说了,在这里说下POSIX这个c语言正则库在对字符串进行正则匹配时取出多个结果的问题。

首先简单说明下POSIX正则库的几个函数和使用方法

第一个函数:int regcomp(regex_t *preg, const char *regex, int cflags);
POSIX C正则库为了提高效率,在将一个字符串与正则表达式进行比较之前,首先要用regcomp()函数对它进行编译,将其转化为regex_t类型。

preg 编译后的regex_t数据
regex 正则表达式
cflags 设置相关标志,包括 REG_EXTENDED、REG_ICASE、REG_NOSUB、REG_NEWLINE

正确编译正则表达式则返回0否则返回一个错误码

第二个函数:int regexec(const regex_t *preg, const char *string, size_t nmatch,
regmatch_t pmatch[], int eflags);

该函数的功能就是将编译过后的正则表达式与在进行匹配的字符串进行正则匹配

preg 经regcomp编译后的参数
string 要进行正则匹配的字符串
nmatch pmatch数组的个数
pmatch 该数组中的两个参数rm_so与rm_eo表示匹配之后匹配的字符串在string中的偏移地址的首地址与尾地址
eflags 设置相关标志,包括REG_NOTBOL和REG_NOTEOL

函数返回的结果与regcomp相同

第三个函数:size_t regerror(int errcode, const regex_t *preg, char *errbuf,
size_t errbuf_size);
该函数看名字就能猜到,它是通过错误代码返回错误信息的

errcode 是regcomp或者regexec返回的错误码
preg 是经regcomp编译后的数据
errbuf 返回错误信息的缓冲区
errbuf_size 错误信息缓冲区的大小

该函数返回的结果是错误信息的长度

第四个函数:void regfree(regex_t *preg);
很简单,释放内存的

使用这四个函数就可以进行正则匹配了,使用的方法是先使用regcomp对正则表达式进行编译,然后通过regexec进行正则匹配,匹配成功后会在结构体regmatch_t中的两个参数中设置匹配字符串在字符串的起始位置与结束位的偏移量,而传递给regexec中的regmatch_t结构体是一个数组,所以你一定认为标题中获取多个结果的方法就是设置这个数组的大小。起初我也是这么想的,但当我这么做的时候才发现,结果并非这样,一次调用regexec返回的结果只有一个,没有多个,那么这个结构体数组是怎么回事呢?

man手册中说的是返回的子表达式,这个子表达式是什么?我来举一个例子
假如有这么一个字符串
<title>第一个</title>第二个<title>第三个</title><title>第四个</title>
如何我们想找出这个字符串中界于<title>与</title>之间中的字符串也就是字符串”第一个、第三个、第四个”,那么我们可能会通过这个正则表达式来获取想要的字符串
<title>.[^>]*

但这样获取的字符串中保有所以为了只取<title>与</title>中间的字符串我们可以使用子表达式来完成,那么这样这个正则表达式就是

<title>\(.[^>]*\)

这样我们就可以通过pmatch[1]来定位取得的子表达式中相对于字符串的偏移,所以显然,pmatch[2]表示的是第二个子表达式,pmatch[3]表示的是第三个子表达式,而pmatch[0]则是整个正则表达式匹配的结果,于是想要在字符串中匹配出所有的<title>与</title>中的结果时就需要多次调用regexec函数。

 

既然已经知道了regmatch_t这个结构体数组并不像我们想象中的那样可以返回匹配的多个结果,那么如何在一个字符串中进行多次的regexec调用进行匹配呢?这其实很简单,如何我们需要匹配的字符串是多行的,那么可以按着每一行调用一次regexec进行匹配,但你也看到了,就像上面的例子,你会很有可能在一行中匹配出多个结果,所以我们需要另一种方法,其实也很简单,我们对字符串的指针进行位移形成一个”新的字符串”就可以了。

 

因为regexec匹配后在pmatch[0]中很返回此次匹配字符串的未位偏移量,所以我们只需要将需要进行匹配的字符串的首地址移动到该处并再次进行下一次regexec的调用匹配就可以了,并如此循环,只到全部匹配完成。以上面的例子来说

<title>第一个</title>第二个</title><title>第三个</title><title>第四个</title>

第一次匹配时匹配到的结果是<title>第一个,此时pmatch[0].rm_eo中的数字为strlen(“<title>第一个”),所以我们将这个字符串的首地址进行移动,将首地址移动到<title>第一个后面,这时”新的字符串”就是

</title>第二个</title><title>第三个</title><title>第四个</title>

如此类推就可以匹配到所有的结果。

 

最后以一个匹配百度贴吧的发帖时间与帖子标题为例给出一个c语言源代码

 

下面是一张使用该程序访问linux吧的截图

Screenshot - 02232014 - 01:01:21 AM

–阅读次数(70)

发表评论

电子邮件地址不会被公开。

*