Posix 正则表达式非贪婪匹配

10

在 C 语言中是否有像 Perl 中一样可以使用非贪婪正则表达式的方法呢?我尝试了几种方法,但实际上并没有起作用。

我目前正在使用这个匹配 IP 地址和相应 HTTP 请求的正则表达式,但它是贪婪的,尽管我使用了 *?:

([0-9]{1,3}(\\.[0-9]{1,3}){3})(.*?)HTTP/1.1

在这个例子中,它总是匹配整个字符串:

#include <regex.h>
#include <stdio.h>

int main() {

    int a, i;
    regex_t re;
    regmatch_t pm;
    char *mpages = "TEST 127.0.0.1 GET /test.php HTTP/1.1\" 404 525 \"-\" \"Mozilla/5.0 (Windows NT  HTTP/1.1 TEST";

    a = regcomp(&re, "([0-9]{1,3}(\\.[0-9]{1,3}){3})(.*?)HTTP/1.1", REG_EXTENDED);

    if(a!=0)
        printf(" -> Error: Invalid Regex");

    a = regexec(&re, &mpages[0], 1, &pm, REG_EXTENDED);

    if(a==0) {

        for(i = pm.rm_so; i < pm.rm_eo; i++)
            printf("%c", mpages[i]);
        printf("\n");
    }
    return 0;
}

$ ./regtest

127.0.0.1 GET /test.php HTTP/1.1" 404 525 "-" "Mozilla/5.0 (Windows NT HTTP/1.1


1
你能把你的输入字符串添加到问题中吗?[这对我来说似乎有效。](http://regexr.com?37cvn) - OGHaza
1
我不懂 c,所以无法提供建议,但问题出在你的代码上而不是你的正则表达式。如果你在输入字符串的末尾添加更多内容,很可能会发现它并不匹配第二个 HTTP/1.1,而是返回整个输入字符串。 - OGHaza
您可以使用更准确的IP匹配。请查看此答案:https://dev59.com/UnVD5IYBdhLWcg3wDXF3#106223 - Stephan
我使用了更准确的IP匹配:结果相同,我还在字符串的开头和结尾添加了内容,结果也相同。 - user2212190
最好使用 grep 进行测试,这样您可以重构问题以打击更广泛的“受众”。 - yeyo
显示剩余2条评论
5个回答

8
不,POSIX正则表达式中没有非贪婪量词。但是有一个库可以为C提供类似Perl的正则表达式:http://www.pcre.org/

0

获取正则表达式与下一个单词匹配的暴力方法是:

"([^H]|H[^T]|HT[^T]|HTT[^P]|HTTP{^/]|HTTP/[^1]|HTTP/1[^.]|HTTP/1\\.[^1])*HTTP/1\\.1"

除非你能更聪明地匹配,而这是可能的:HTTP请求

Request-Line   = Method SP Request-URI SP HTTP-Version CRLF

右侧的非终结符没有匹配嵌入空格。因此:

"[0-9]{1,3}(\\.[0-9]{1,3}){3} [^ ]* [^ ]* HTTP/1\\.1"

由于您只为整个表达式匹配分配空间,或者将括号放回以获取各个部分。


0
a = regcomp(&re, "([0-9]{1,3}(\\.[0-9]{1,3}){3})(.*?)HTTP/1.1",  REG_EXTENDED|REG_ENHANCED);  

旧时代没有这个宏

#if __MAC_OS_X_VERSION_MIN_REQUIRED  >= __MAC_10_8 \
 || __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_6_0
#define REG_ENHANCED    0400    /* Additional (non-POSIX) features */
#endif

0

正如我之前在评论中所说的,使用 grep -E 来运行带有 POSIX 正则表达式的测试,这样开发时间会得到改善。不管怎样,看起来你的问题是与正则表达式有关,而不是与缺失的功能有关。

对于你想从请求中获取什么不太清楚...假设你只想要 IP 地址、HTTP 动词和资源,可以使用以下正则表达式。

regcomp(&re, "\\b(.?[0-9])+\\s+(GET|POST|PUT)\\s+([^ ]+)", REG_EXTENDED);

请注意,已经做出了几个假设。例如,此正则表达式假定IP地址格式正确,还假定使用HTTP动词(GET、POST、PUT)的请求。请根据您的需要进行相应的编辑。

-1
在你的代码中,pm 应该是一个 regmatch_t 数组,并且在你的情况下,应该至少有 2 到 4 个元素,具体取决于你想要捕获哪些 () 子表达式。
你只有一个元素。第一个元素 pm[0] 总是获取与整个正则表达式匹配的文本。这就是你将要得到的。而 pm[1] 将获取第一个 () 子表达式(即 IP 地址)的文本,pm[3] 将获取与你的 (.*?) 表达式匹配的文本。
但是,正如上面所述(由 Wumbley, W. Q.),POSIX 正则表达式库可能不支持非贪婪量词。

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