Почему regexec() в posix c всегда возвращает первое совпадение, как он может возвращать все позиции соответствия только один раз?

Теперь, когда я хочу вернуть все позиции соответствия в str, например:

abcd123abcd123abcd

Предположим, что я хочу получить все "abcd", я должен использовать regexec(), получить первую позицию: 0, 3, затем буду использовать:

123abcd123abcd

в качестве новой строки для повторного использования regexec() и т.д. Я прочитал инструкцию по regexec(), в которой говорится:

int regexec(const regex_t *preg, const char *string, size_t nmatch,
               regmatch_t pmatch[], int eflags);
nmatch and pmatch are used to provide information regarding the location of any 
matches.

но почему это не работает? Это мой код:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>

int main(int argc, char **argv)
{
   int i = 0;
   int res;
   int len;
   char result[BUFSIZ];
   char err_buf[BUFSIZ];
   char* src = argv[1];  

   const char* pattern = "\\<[^,;]+\\>";
   regex_t preg;

   regmatch_t pmatch[10];

   if( (res = regcomp(&preg, pattern, REG_EXTENDED)) != 0)
   {
      regerror(res, &preg, err_buf, BUFSIZ);
      printf("regcomp: %s\n", err_buf);
      exit(res);
   }

   res = regexec(&preg, src, 10, pmatch, REG_NOTBOL);
   //~ res = regexec(&preg, src, 10, pmatch, 0);
   //~ res = regexec(&preg, src, 10, pmatch, REG_NOTEOL);
   if(res == REG_NOMATCH)
   {
      printf("NO match\n");
      exit(0);
   }
   for (i = 0; pmatch[i].rm_so != -1; i++)
   {
      len = pmatch[i].rm_eo - pmatch[i].rm_so;
      memcpy(result, src + pmatch[i].rm_so, len);
      result[len] = 0;
      printf("num %d: '%s'\n", i, result);
   }
   regfree(&preg);
   return 0;
}

./regex 'hello, world'

вывод:

num 0: 'hello'

это мои отзывы:

num 0: 'hello'
num 1: 'world'

Ответ 1

regexec выполняет регулярное совпадение. Как только совпадение найдено, regexec вернет ноль (то есть успешное совпадение). Параметр pmatch будет содержать информацию об этом совпадении. Первый индекс массива (т.е. Нуль) будет содержать полное совпадение, последующие индексы массива содержат информацию о группах/подписях захвата.

Чтобы продемонстрировать:

const char* pattern = "(\\w+) (\\w+)";

совпадающий с "hello world", будет выводиться:

num 0: 'hello world'  - entire match
num 1: 'hello'        - capture group 1
num 2: 'world'        - capture group 2

(см. действие)

В большинстве сред с регулярными выражениями поведение, которое вы искали, могло быть получено с помощью глобального модификатора:/g. Regexec не предоставляет этот модификатор в качестве флага и не поддерживает модификаторы. Поэтому вам нужно будет зациклиться, в то время как regexec возвращает ноль, начиная с последнего символа предыдущего совпадения, чтобы получить все совпадения.

Глобальный модификатор также недоступен с использованием библиотеки PCRE (известная библиотека регулярных выражений C). В man-страницах PCRE есть об этом:

Вызывая pcre_exec() несколько раз с соответствующими аргументами, вы может имитировать параметр Perl/g