C正则表达式:提取实际匹配

9co*_*an9 4 c regex char pattern-matching

我在C中使用正则表达式(使用"regex.h"库).在为regcomp(...)和regexec(...)设置标准调用(和检查)之后,我只能设法打印与我编译的正则表达式匹配的实际子字符串.根据手册页,使用regexec意味着将子串匹配存储在称为"regmatch_t"的结构中.结构只包含rm_so和rm_eo来引用我所理解的内存中匹配子字符串的字符地址,但我的问题是我如何才能将这些用于偏移和两个指针来提取实际的子字符串并将其存储到一个数组(理想情况下是一个2D字符串数组)?

它只在您打印到标准输出时有效,但每当您尝试使用相同的设置但将其存储在字符串/字符数组中时,它会存储最初用于匹配表达式的整个字符串.此外,打印声明中的"%.*s"是什么?我想这是一个正则表达式,可以正确地读取指向字符数组的指针.我只想将匹配的子串存储在一个集合中,这样我就可以在我的软件中的其他地方使用它们了.

背景:p和p2都指向设置为指向字符串开头的指针,然后在下面的代码中输入while循环:[编辑:"匹配"是一个2D数组,意味着最终存储子字符串匹配并被预先分配/初始化在主循环之前,你看到下面]

int ind = 0;
while(1){
    regExErr1 = regexec(&r, p, 10, m, 0);
    //printf("Did match regular expr, value %i\n", regExErr1);
    if( regExErr1 != 0 ){ 
        fprintf(stderr, "No more matches with the inherent regular expression!\n"); 
        break; 
    }   
    printf("What was found was: ");
    int i = 0;
    while(1){
        if(m[i].rm_so == -1){
            break;
        }
        int start = m[i].rm_so + (p - p2);
        int finish = m[i].rm_eo + (p - p2);
        strcpy(matches[ind], ("%.*s\n", (finish - start), p2 + start));
        printf("Storing:  %.*s", matches[ind]);
        ind++;
        printf("%.*s\n", (finish - start), p2 + start);
        i++;
    }
    p += m[0].rm_eo; // this will move the pointer p to the end of last matched pattern and on to the start of a new one
}
printf("We have in [0]:  %s\n", temp);
Run Code Online (Sandbox Code Playgroud)

Jon*_*ler 8

有很多正则表达式包,但你的似乎与POSIX中的那个匹配:regcomp()等等.

它定义的两个结构<regex.h>是:

  • regex_t至少包含带size_t re_nsub括号的子表达式的数量.

  • regmatch_t至少包含regoff_t rm_so从字符串开始到子字符串开始regoff_t rm_eo的字节偏移量,以及从子字符串结束后第一个字符的字符串开头的字节偏移量.

请注意,'offsets'不是指针,而是索引到字符数组中.

执行功能是:

  • int regexec(const regex_t *restrict preg, const char *restrict string, size_t nmatch, regmatch_t pmatch[restrict], int eflags);

您的打印代码应为:

for (int i = 0; i < r.re_nsub; i++)
{
    int start = m[i].rm_so;
    int finish = m[i].rm_eo;
    strcpy(matches[ind], ("%.*s\n", (finish - start), p + start));
    printf("Storing:  %.*s\n", (finish - start), matches[ind]);
    ind++;
    printf("%.*s\n", (finish - start), p + start);
}
Run Code Online (Sandbox Code Playgroud)

请注意,应升级此代码以确保字符串副本不会溢出目标字符串.标记字符串的开头和结尾也是一个好主意,例如:

    printf("<<%.*s>>\n", (finish - start), p + start);
Run Code Online (Sandbox Code Playgroud)

这使得整个堆更容易看到空间等.

[将来,请尝试提供SSCCE(简短,自包含,正确的示例),以便人们可以更轻松地提供帮助.

这是我创建的SSCCE,可能是为了回应2010年的另一个SO问题.这是我保留的一些程序之一,我称之为"小插曲"; 显示某些功能本质的小程序(例如POSIX正则表达式,在本例中).我发现它们有用作记忆慢跑者.

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

#define tofind    "^DAEMONS=\\(([^)]*)\\)[ \t]*$"

int main(int argc, char **argv)
{
    FILE *fp;
    char line[1024];
    int retval = 0;
    regex_t re;
    regmatch_t rm[2];
    //this file has this line "DAEMONS=(sysklogd network sshd !netfs !crond)"
    const char *filename = "/etc/rc.conf";

    if (argc > 1)
        filename = argv[1];

    if (regcomp(&re, tofind, REG_EXTENDED) != 0)
    {
        fprintf(stderr, "Failed to compile regex '%s'\n", tofind);
        return EXIT_FAILURE;
    }

    fp = fopen(filename, "r");
    if (fp == 0)
    {
        fprintf(stderr, "Failed to open file %s (%d: %s)\n", filename, errno, strerror(errno));
        return EXIT_FAILURE;
    }

    while ((fgets(line, 1024, fp)) != NULL)
    {
        line[strlen(line)-1] = '\0';
        if ((retval = regexec(&re, line, 2, rm, 0)) == 0)
        {
            printf("<<%s>>\n", line);
            printf("Line: <<%.*s>>\n", (int)(rm[0].rm_eo - rm[0].rm_so), line + rm[0].rm_so);
            printf("Text: <<%.*s>>\n", (int)(rm[1].rm_eo - rm[1].rm_so), line + rm[1].rm_so);
            char *src = line + rm[1].rm_so;
            char *end = line + rm[1].rm_eo;
            while (src < end)
            {
                size_t len = strcspn(src, " ");
                if (src + len > end)
                    len = end - src;
                printf("Name: <<%.*s>>\n", (int)len, src);
                src += len;
                src += strspn(src, " ");
            }
        }
    } 
    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

这旨在查找从DAEMONS=文件开始的特定行/etc/rc.conf.您可以轻松地将其调整到您的目的.