使用PCRE正则表达式得到奇怪的答案

3
我正在使用C语言中的PCRE正则表达式库(http://www.pcre.org/)来解析和匹配我的HTML字符串。为了简化我的问题,假设我有源字符串:"aaa: bbbb:",和我的模式:a(.*?):|b(.*?):,符号?表示它是一个非贪婪匹配,所以答案应该是两个匹配项:一个是"aaa:",另一个是"bbbb:"

然后我编写了以下程序:

char *src = "aaa:  bbbb:";
char *pattern = "a(.*?):|b(.*?):";
pcre *re = NULL;

//---missing out---

re = pcre_compile(pattern,  // pattern,  
                  0,            // options,   
                  &error,       // errptr,   
                  &erroffset,   // erroffset,  
                  NULL);        // tableptr, 
while (
      (rc = pcre_exec(re,     // regex ptr,   
               NULL,          // extra arg,   
               src,           // subject,   
               strlen(src),   // length,   
               0,             // startoffset,   
               0,             // options,   
               ovector,       // ovector,   
               OVECCOUNT)     // ovecsize,   
      )!=PCRE_ERROR_NOMATCH)  
    {
       printf("\nOK, string has matched ...there are %d matchups\n\n",rc); //  
       for (i = 0; i < rc; i++)
       {
            char *substring_start = src + ovector[2*i];
            int substring_length = ovector[2*i+1] - ovector[2*i];
            printf("$%2d: %.*s length: %d\n", i, substring_length, substring_start,substring_length);
       }
       src = src + ovector[1];  // to move the src pointer to the end offset of current matchup
       if (!src) break;
    }
pcre_free(re);

我得到了我的结果:
Source : aaa:  bbbb:
Pattern: "a(.*?):|b(.*?):"

OK, string has matched ...there are 2 matches

$ 0: aaa: length: 4
$ 1: aa length: 2 

OK, string has matched ...there are 3 matches

$ 0: bbbb: length: 5
$ 1:  length: 0
$ 2: bbb length: 3

我在想,我是怎么得到答案"$ 1: length: 0"的?

//----------------------------------------------------------------------------------------

@Jonathan Leffler 我认为你的答案是正确的。

刚刚我尝试了

Source: "aaa: bbb: ccc:"
Pattern: "c(.+?):|a(.+?):|b(.+?):"

而且得到的结果如下:
$ 0: aaa: length: 4
$ 1:  length: 0
$ 2: aa length: 2

$ 0: bbbb: length: 5
$ 1:  length: 0
$ 2:  length: 0
$ 3: bbb length: 3

$ 0: cccc: length: 5
$ 1: ccc length: 3

这证明了你的答案是相反的:
当找到匹配时,正则表达式的捕获就停止了,所以在尝试匹配后,被捕获,结果的第一行显示整个字符串,#2显示结果偏移与的替代项匹配。
对于,它最终被正则表达式捕获,这解释了两个。
对于,它首先被捕获,因此没有。

你能否修改示例源代码,使其能够编译通过? - thuovila
可能是因为您使用了 * 而不是 + - jcubic
4个回答

1
正则表达式中有两个捕获,每个选择项都有一个。但是,捕获是从左到右编号的。在第二种情况下,第一个 ($1) 捕获为空;在匹配的内容中没有 a,因此第一次捕获为空;第二个 ($2) 捕获包含了您期望的 b
令人惊讶的是,在第一次匹配时,第二个捕获没有指定任何内容。我猜如果它们没有数据,那么捕获就是空的。

0

* 表示匹配任意数量(包括零)的字符,也就是匹配“无”。应该使用 + 字符,表示“至少匹配 1 次”。


它没有回答为什么它在那里的问题。 - nhahtdh

0

尝试使用模式char *pattern = "a+?:|b+?:";

编辑注意到只有"a+:|b+:"也可以工作。


1
这个问题是在问为什么会发生这种情况,而不是在寻求关于正则表达式的建议。这个正则表达式很可能只是用来展示这个奇怪现象的一个例子。 - nhahtdh

0

模式:

a(.*?):

这个模式意味着查找一个未捕获的 'a',后面跟着任意数量的任何字符的捕获,修改为返回最小匹配模式,然后是一个未捕获的 ':'。

如果您考虑字符串:

aaa:

现在考虑冒号前面的最后一个 'a':
a:

它匹配模式 - 一个 'a',后面什么也没有,再跟着一个冒号。'nothing'被捕获,这就是为什么你得到了一个零长度的结果。


第二个匹配捕获的整个字符串是 bbbb;涉及 a: 的解释显然不适用。 - Jonathan Leffler
抱歉,我没有给出关于我的真正问题的好例子,但是你的答案无法解释为什么aaa:的结果中有length:0 - Kung Pao Chicken

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接