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

我在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); 

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

它在中定义的两个结构是:

  • regex_t至少包含size_t re_nsub ,括号内的子表达式的数量。

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

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

执行function是:

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

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

  printf("<<%.*s>>\n", (finish - start), p + start); 

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

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

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

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

这是为了在文件/etc/rc.conf找到以DAEMONS=开头的特定行。 您可以轻松地适应您的目的。

由于g ++正则表达式被窃听,直到谁知道什么时候,你可以使用我的代码(许可证:AGPL,没有保证,你自己的风险……)

 /** * regexp (License: AGPL3 or higher) * @param re extended POSIX regular expression * @param nmatch maximum number of matches * @param str string to match * @return An array of char pointers. You have to free() the first element (string storage). the second element is the string matching the full regex, then come the submatches. */ char **regexp(char *re, int nmatch, char *str) { char **result; char *string; regex_t regex; regmatch_t *match; int i; match=malloc(nmatch*sizeof(*match)); if (!result) { fprintf(stderr, "Out of memory !"); return NULL; } if (regcomp(&regex, re, REG_EXTENDED)!=0) { fprintf(stderr, "Failed to compile regex '%s'\n", re); return NULL; } string=strdup(str); if (regexec(&regex,string,nmatch,match,0)) { #ifdef DEBUG fprintf(stderr, "String '%s' does not match regex '%s'\n",str,re); #endif free(string); return NULL; } result=malloc(sizeof(*result)); if (!result) { fprintf(stderr, "Out of memory !"); free(string); return NULL; } for (i=0; i=0) { string[match[i].rm_eo]=0; ((char**)result)[i]=string+match[i].rm_so; #ifdef DEBUG printf("%s\n",string+match[i].rm_so); #endif } else { ((char**)result)[i]=""; } } result[0]=string; return result; }