【问题标题】:Saving regex matched strings to an array of strings将正则表达式匹配的字符串保存到字符串数组
【发布时间】:2015-05-15 14:36:03
【问题描述】:

所以我刚开始拿起 c 我的最终目标是编写一个函数,用正则表达式搜索字符串并返回匹配数组。

我遇到的最大问题是将字符串保存到内存中,这些字符串可以在作为参数传入的指针中返回或引用。

我真的很想知道有多少匹配项,这样我就可以做类似 c# 的事情; if(matches.Count() > 0) { /* we have a match! */ } 然后根据我最终传入的模式获取每个匹配组的结果字符串。

我知道这是不正确的,并且在实践中可能还有其他一些错误,但这是我试图找出它的代码,我试图通过阅读指针、结构、char 数组..etc 来解决这个问题

typedef struct
{
    char *match;
} Matches;

int main()
{
    regex_t regex;
    int reti;
    char msgbuf[100];
    int max_matches = 10;
    regmatch_t m[max_matches];

    char str[] = "hello world";

    reti = regcomp(&regex, "(hello) (world)", REG_EXTENDED);
    if( reti )
    {
        fprintf(stderr, "Could not compile regex\n");
        exit(1);
    }

    reti = regexec(&regex, str, (size_t) max_matches, m, 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);
    }

    char *p = str;
    int num_of_matches = 0;

    Matches *matches;

    int i = 0;
    for(i = 0; i < max_matches; i++)
    {
        if (m[i].rm_so == -1) break;

        int start = m[i].rm_so + (p - str);
        int finish = m[i].rm_eo + (p - str);

        if (i == 0)
            printf ("$& is ");
        else
            printf ("$%d is ", i);

        char match[finish - start + 1];
        memcpy(match, str + start, finish - start);
        match[sizeof(match)] = 0;

        matches[i].match = match; //Need to get access to this string in an array outside of the loop

        printf ("'%.*s' (bytes %d:%d)\n", (finish - start), str + start, start, finish);

        num_of_matches++;
    }
    p += m[0].rm_eo;

    for(i = 0; i < num_of_matches; i++)
    {
        printf("'%s'\n", matches[i].match);
    }

    /* Free compiled regular expression if you want to use the regex_t again */
    regfree(&regex);

    return 0;
}

当我认为我只匹配“世界”时我注意到当我注释掉 printf 语句时,最后一个 printf 语句返回空字符或随机字符。

【问题讨论】:

    标签: c


    【解决方案1】:

    您的问题主要是与 C 字符串有关的内存问题。

    首先,为匹配项定义一个数组:

    Matches *matches;
    

    这定义了一个指向你的匹配结构的指针,但是这个指针是未初始化的并且没有指向任何合理的地方。相反,您应该定义一个匹配数组:

    Matches matches[max_matches];
    

    这将为您提供 10 个(本地)匹配项供您访问。

    接下来,您定义一个本地字符串以将匹配项保存为可变长度数组 (VLA):

    char match[finish - start + 1];
    

    这一次,您已经分配了足够的空间来保存子字符串。但是这个 char 缓冲区是本地的,当你到达 for 循环体的右括号时,它就会消失。下一次循环可能会使用相同的内存。循环后访问此内存是非法的。

    一种解决方案是使用malloc在堆上分配内存:

    char *match = malloc(finish - start + 1);
    

    请注意,稍后您必须使用free 再次显式释放资源。

    您复制子字符串并以空字符结尾。但是,当您这样做时,您不会正确获取空字符的位置:

    match[sizeof(match)] = 0;
    

    sizeof 是一个编译时操作数,它告诉您给定表达式的类型在内存中占用了多少字节。当您使用 VLA 时,sizeof(match) 位于 thatb 缓冲区末尾之后。现在我们使用一个指向已分配内存的指针,其中sizeof 是指针的大小。

    sizeof 经常与strlen 混淆,但在这里您不能使用strlen,因为match 尚未按照strlen 的要求以空值终止。但是你知道字符串的大小,你自己的:

    match[finish - start] = 0;
    

    你也不需要指针p,只需定义:

    int start = m[i].rm_so;
    int finish = m[i].rm_eo;
    

    所以:

    • 确保在要存储内容时实际分配内存。
    • 请注意不要在访问本地内存之前使其失效。 (这方面最令人震惊的例子是从函数返回本地数组的地址。您的情况不那么令人反感,但也不那么明显。)
    • 可以使用malloc 分配长寿命内存。此类内存不会被垃圾回收,必须使用 free 显式释放。
    • sizeof 是编译时操作数。它是 malloc 等原始内存函数所需的拐杖。 (我在这里省略了sizeof,因为sizeof(char) 保证为1。)

    在 C 中使用字符串不好玩吗?

    【讨论】:

    • 这个答案你应该得到多于一分。非常感谢您向我解释。所以如果我释放matches 会释放我为循环中每个match 分配的所有内存吗?还是我必须明确释放那些?
    • 看起来我必须循环并明确地释放每个。哈哈,在 c 中使用字符串肯定是“有趣的”。
    • 是的,您必须在循环中 free(matches[i]) malloced 数据。你甚至不能free(matches),因为它不是你malloced 的东西。规则是:从malloc 收到的每个指针对应一个free
    • 字符串无疑是 C 语言的难点,尤其是如果您已经了解其他具有更好字符串支持的语言。
    猜你喜欢
    • 2022-01-17
    • 1970-01-01
    • 2011-11-08
    • 2012-06-05
    • 2013-12-25
    • 1970-01-01
    相关资源
    最近更新 更多