在C中,如何获取捕获组RegEx?

时间:2018-09-01 15:29:14

标签: c regex

这是我遇到的C函数:

char get_access_token(char *client_credentials)
{
    regex_t regex;
    int reti;
    char msgbuf[100];
    reti = regcomp(&regex, "\\\"access_token\\\".\\\"(.*?)\\\"", 0);

    regmatch_t pmatch[1];
    if (reti) {
        fprintf(stderr, "Could not compile regex\n");
        exit(1);
    }

    reti = regexec(&regex, client_credentials, 1, pmatch, 0);
    if (!reti) {
        puts("Match");
    } else if (reti == REG_NOMATCH) {
        puts("No match");
    } else {
        regerror(reti, &regex, msgbuf, sizeof(msgbuf));
        fprintf(stderr, "Regex match failed: %s\n", msgbuf);
        exit(1);
    }

    return (char) "";
}

我要解析的字符串是JSON字符串,我不在乎实际结构,我只在乎访问令牌。

它应该看起来像这样:

{"access_token": "blablablabal"}

我希望我的函数只返回“ blablablabla”

我要使用的RegEx是这样的:

\"access_token"."(.*?)"

但是我无法在变量pmatch中找到该数组中的两个数字,我真的不知道这些数字是什么意思。

我在做什么错?

P.S。我是C菜鸟,我在学习。

2 个答案:

答案 0 :(得分:1)

有几个问题。您的正则表达式中有错别字。而且您正在尝试将扩展的正则表达式功能与POSIX正则表达式一起使用。

首先是错别字。

reti = regcomp(&regex, "\\\"access_token\\\".\\\"(.*?)\\\"", 0);
                                            ^

应该是:

reti = regcomp(&regex, "\\\"access_token\\\": \\\"(.*?)\\\"", 0);

然后,我们不需要在正则表达式中转义引号。这样更易于阅读。

reti = regcomp(&regex, "\"access_token\": \"(.*?)\"", 0);

这仍然不起作用,因为它使用的是基本POSIX正则表达式所没有的功能。捕获组必须在基本POSIX正则表达式中转义。可以使用REG_EXTENDED来解决。 *?非贪婪运算符是从Perl借来的增强的non-POSIX功能。您可以通过REG_ENHANCED获得它们。

reti = regcomp(&regex, "\"access_token\": \"(.*?)\"", REG_ENHANCED|REG_EXTENDED);

但出于所有相同的原因,we don't parse HTML with a regex请勿尝试使用正则表达式解析JSON。使用JSON库,例如json-glib

答案 1 :(得分:1)

好吧,您的pmatch数组必须至少包含两个元素,您可能知道,组0是整个匹配的正则表达式,并且填充了整个正则表达式(例如所有正则表达式都用圆括号对进行了舍入)(您想要将组1括起来,所以pmatch[1]将被第一个子表达式组的信息填充。

如果您查看文档,则pmatch元素具有两个字段,这些字段索引了与组匹配的原始缓冲区中的起始索引,而则位于最后一个索引之后组中字符串结束的位置。这些字段名称分别为rm_sorm_eo,与pmatch[0]中的字段名称一样,它们分别表示常规(子)表达式开始和结束处的索引。

您可以使用以下方式打印匹配的元素(一旦知道它们是有效的,请参阅doc):

#define SIZEOF(arr) (sizeof arr / sizeof arr[0])
...
regmatch_t pmatch[2]; /* for global regexp and group 1 */
...
/* you don't need to escape " chars, they are not special for regcomp,
 * they do, however, for C, so only one \ must be used. */
res = regcomp(&regex, "\"access_token\".\"([^)]*)\"", 0);
...
reti = regexec(&regex, client_credentials, SIZEOF(pmatch), pmatch, 0);

for (i = 0; i < regex.re_nsub; i++) {
    char *p = client_credentials + pmatch[i].rm_so; /* p points to beginning of match */
    size_t l = pmatch[i].rm_eo - pmatch[i].rm_so; /* match length */
    printf("Group #%d: %0.*s\n", i, l, p);
}

我很抱歉提交一小段代码,而不是一个可验证且完整的示例,但是由于您没有在问题中这样做(因此我们无法测试您的示例代码),因此我不会在答案中这样做。因此,该代码未经测试,可能会出错。提防这一点。

测试样本响应需要时间,如果我们首先使您的样本代码完全可测试,则情况更糟。 (这是对初学者的抱怨-和一些非初学者的-不发布Minimal, Complete, and Verifiable example的使用。)