【问题标题】:How can I extract submatches using C regex如何使用 C 正则表达式提取子匹配
【发布时间】:2021-07-06 01:17:48
【问题描述】:

我已经使 GNU 正则表达式库的工作方式与我在大约 2 年前编写的一个广泛的文本处理算法中所宣传的完全一样,但不幸的是,该平台已经消失,我不知道它的版本是比下面引用的版本旧还是新.

代码如下:

// GNU libc version: 2.28
// gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0

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

int main() {

    regex_t preg;
    char str[] = "dave";
    char regex[] = "\\(.\\)ave";

    // flag REG_EXTENDED with unescaped parens in the r.e. doesn't fix anything
    int ret, cflags = REG_ICASE;
    
    // the elements of unused pmatches used to be set to -1 by regexec, but no longer. a clue perhaps.

    regmatch_t pmatch[2] = {{-1,-1},{-1,-1}};

    ret = regcomp(&preg, regex, cflags);
    if (ret) {
        puts("regcomp fail");
        return ret;
    }
    else
        // preg.re_nsub contains the correct number of groups that regcomp recognized in the r.e. Tests succeeded for 0, 1, 2, and 3 groups.
        printf("regcomp ok; re_nsub=%zu\n", preg.re_nsub);

    ret = regexec(&preg, str, 1, pmatch, 0);

    if(ret)
        puts("no match");
    else {
        printf("match offsets are %d %d\n", pmatch[0].rm_so, pmatch[0].rm_eo);
        printf("match[0]=%*s<\n", pmatch[0].rm_eo, &str[pmatch[0].rm_so]);

        printf("submatch offsets are %d %d\n", pmatch[1].rm_so, pmatch[1].rm_eo);
        if(pmatch[1].rm_so != -1)
            printf("match[1]=%*s<\n", pmatch[1].rm_eo, &str[pmatch[1].rm_so]);
    }
    return 0;
}
/*
output:
regcomp ok; re_nsub=1
match offsets are 0 4
match[0]=dave<
submatch offsets are -1 -1
*/

【问题讨论】:

  • 可能是cflags = REG_ICASE | REG_EXTENDED?
  • 你需要什么输出?您的正则表达式模式不包含反向引用,并且您没有用对组的反向引用替换任何内容。
  • REG_EXTENDED 没有帮助
  • 反向引用出现在匹配中,而不是模式中。该模式包含一个带括号的字母,该字母应该在结果中被反向引用,即 pmatch[1] 的偏移量应该是......无论如何,它们应该是它们被初始化的东西。
  • 所以,您说的是捕获组捕获,而不是反向引用。您还需要第 1 组索引还是文本?

标签: c regex posix backreference capture-group


【解决方案1】:

您没有获得第一个捕获组的偏移量的问题是您将1 作为第三个size_t __nmatch 参数传递给regexec

1 值应更改为 2,因为每当 \(.\)ave 正则表达式匹配时将有两个组:第 0 组将保存整个匹配,第 1 组将保存第一个捕获组值。

所以,你需要使用

ret = regexec(&preg, str, 2, pmatch, 0);
//                       ^^^

此外,要打印您可以使用的第 1 组值

if(pmatch[1].rm_so != -1) {
    printf("match[1]=%.*s<\n", pmatch[1].rm_eo, &str[pmatch[1].rm_so]);
}

this C demo:

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

int main() {

    regex_t preg;
    char str[] = "dave";
    char regex[] = "\\(.\\)ave";

    // flag REG_EXTENDED with unescaped parens in the r.e. doesn't fix anything
    int ret, cflags = REG_ICASE;
    
    // the elements of unused pmatches used to be set to -1 by regexec, but no longer. a clue perhaps.

    regmatch_t pmatch[2] = {{-1,-1},{-1,-1}};

    ret = regcomp(&preg, regex, cflags);
    if (ret) {
        puts("regcomp fail");
        return ret;
    }
    else
        // preg.re_nsub contains the correct number of groups that regcomp recognized in the r.e. Tests succeeded for 0, 1, 2, and 3 groups.
        printf("regcomp ok; re_nsub=%zu\n", preg.re_nsub);

    ret = regexec(&preg, str, 2, pmatch, 0); // 1 changed to 2 as there is Group 0 (whole match) and Group 1 (for the first capturing group)

    if(ret)
        puts("no match");
    else {
        printf("match offsets are %d %d\n", pmatch[0].rm_so, pmatch[0].rm_eo);
        printf("match[0]=%*s<\n", pmatch[0].rm_eo, &str[pmatch[0].rm_so]);

        printf("submatch offsets are %d %d\n", pmatch[1].rm_so, pmatch[1].rm_eo);
        if(pmatch[1].rm_so != -1) {
            printf("match[1]=%.*s<\n", pmatch[1].rm_eo, &str[pmatch[1].rm_so]);
        }
    }
    return 0;
}
/*
regcomp ok; re_nsub=1
match offsets are 0 4
match[0]=dave<
submatch offsets are 0 1
match[1]=d<
*/

【讨论】:

  • 确实是的!!!我真的不认为 gnu 实现会被破坏。
  • 另外,我可以省略 pmatch 的初始化并使用 cflags = REG_EXTENDED | ...避免模式中所有令人讨厌的反斜杠。谢谢 Stribiżew 先生。
猜你喜欢
  • 2011-01-12
  • 1970-01-01
  • 2021-06-11
  • 2015-03-08
  • 1970-01-01
  • 2013-02-02
相关资源
最近更新 更多