将正则表达式匹配的字符串保存到字符串数组中

时间:2015-05-15 14:36:04

标签: c

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

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

我真的想要一种方法来判断有多少匹配,所以我可以做一些像c#等效的东西; if(matches.Count() > 0) { /* we have a match! */ } 然后根据我最终传入的模式获取每个匹配组的结果字符串。

我知道这是不正确的,并且在实践中可能还有其他一些错误,但是这里是我试图弄清楚读取指针,结构,字符数组等的代码。等等

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语句返回了空字符或随机字符。

1 个答案:

答案 0 :(得分: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)是在该缓冲区结束后的一个。现在我们使用指向已分配内存的指针,其中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 fun中不使用字符串吗?