【问题标题】:In C, How to get capturing group RegEx?在 C 中,如何获取捕获组 RegEx?
【发布时间】:2018-09-03 21:17:31
【问题描述】:

这是我遇到问题的 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 中找不到,我只在那个数组中找到了两个数字,我真的不知道这些数字是什么意思。

我做错了什么?

附:我是C菜鸟,我只是在学习。

【问题讨论】:

    标签: c regex


    【解决方案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 借来的增强的非 POSIX 功能。您可以通过REG_ENHANCED 获得它们。

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

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

    【讨论】:

    • 我尝试使用该库,但话又说回来,我遇到了另一种问题。这就是为什么我认为只解析 JSON 会更容易。虽然我不是初学者,但我对 C 语言非常陌生,所以遇到了麻烦。
    • @ILikeTacos C 是无情的。我想您可能在共享库方面遇到了一些麻烦。如果遇到麻烦,不妨试试 json-glib 并提出问题。
    • 我确实在共享库方面遇到了很多麻烦,但我想通了。我需要做的就是将库的路径传递给链接器,但我的头撞到了墙上几秒钟。完成安装后,我可能会向 SO 发送有关 json-glib 的问题。
    • @ILikeTacos pkg-config 在链接库时可以为您省去很多麻烦。
    • 我认为代码可以用\" 替换出现的\\\"。在正则表达式中,双引号不是特殊的(不是元字符),也不需要反斜杠转义。
    【解决方案2】:

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

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

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

    #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);
    }
    

    对于提交代码的 sn-p 而不是可验证且完整的示例,我深表歉意,但由于您没有在问题中这样做(因此我们无法测试您的示例代码)我不会在答案中这样做.所以,代码没有经过测试,我这边可能会有错误。小心这个。

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

    【讨论】:

      猜你喜欢
      • 2017-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-07
      • 2010-12-25
      • 1970-01-01
      相关资源
      最近更新 更多