Массив структур regmatch_t
используется для представления местоположения подвыражений в регулярном выражении.
#include <regex.h>
typedef struct {
regoff_t rm_so; /* индекс байта в строке в начале сопоставления*/
regoff_t rm_eo; /* индекс байта в строке в конце сопоставления*/
} regmatch_t;
Первый элемент regmatch_t
описывает всю совпавшую строку; обратите внимание, что вся эта строка содержит любой символ начала строки, включая хвостовой символ новой строки, независимо от того, задано ли значение REG_NEWLINE
.
Следующие элементы массива хранят подвыражения, заключенные в скобки, в том порядке, в котором они присутствуют в регулярном выражении, в порядке расположения открывающих скобок. (В коде на языке С элемент i
эквивалентен выражению замены \i
в программах sed
или awk
.) В несовпадающих подвыражениях член regmatch_t.rm_so
имеет значение -1
.
В следующем коде производится сопоставление строки с регулярным выражением, содержащим подвыражения. После сопоставления на экран выводятся все совпавшие подвыражения.
1: /* match.с */
2:
3: #include <alloca.h>
4: #include <sys/types.h>
5: #include <regex.h>
6: #include <stdlib.h>
7: #include <string.h>
8: #include <stdio.h>
9:
10: void do_regerror(int errcode, const regex_t *preg) {
11: char *errbuf;
12: size_t errbuf_size;
13:
14: errbuf_size = regerror(errcode, preg, NULL, 0);
15: errbuf = alloca(errbuf_size);
16: if (!errbuf) {
17: perror("alloca");
18: return;
19: }
20:
21: regerror(errcode, preg, errbuf, errbuf_size);
22: fprintf(stderr, "%s\n", errbuf);
23: }
24:
25: int main() {
26:
27: regex_t p;
28: regmatch_t *pmatch;
29: int rerr;
30: char *regex = "(^(.*[^\\])#.*$)|(^[^#]+$)";
31: char string[BUFSIZ+1];
32: int i;
33:
34: if ((rerr = regcomp(&p, regex, REG_EXTENDED | REG_NEWLINE))) {
35: do_regerror(rerr, &p);
36: }
37:
38: pmatch = alloca(sizeof(regmatch_t) * (p.re_nsub+1));
39: if (!pmatch) {
40: perror("alloca");
41: }
42:
43: printf("Введите строку: ");
44: fgets(string, sizeof(string), stdin);
45:
46: if ((rerr = regexec(&p, string, p.re_nsub+1, pmatch, 0))) {
47: if (rerr == REG_NOMATCH) {
48: /* эту ситуацию может обработать regerror,
49: * но зачастую она обрабатывается особым образом
50: */
51: printf("Строка не совпадает с %s\n", regex);
52: } else {
53: do_regerror(rerr, &p);
54: }
55: } else {
56: /* сопоставление закончено */
57: printf("Строка совпадает с регулярным выражением %s\n", regex);
58: for (i = 0; i <= p.re_nsub; i++) {
59: /* вывод на экран совпавшей части (частей) строки */
60: if (pmatch[i].rm_so != -1) {
61: char *submatch;
62: size_t matchlen = pmatch[i].rm_eo - pmatch[i].rm_so;
63: submatch = malloc(matchlen+1);
64: strncpy(submatch, string+pmatch[i].rm_so,
65: matchlen);
66: submatch[matchlen] = '\0';
67: printf("совпавшее подвыражение %d: %s\n", i,
68: submatch);
69: free(submatch);
70: } else {
71: printf ("нет совпадения с подвыражением %d\n", i);
72: }
73: }
74: }
75: exit(0);
76: }
В примере регулярного выражения из программы match.с
имеется три подвыражения. Первое из них представляет собой всю строку, содержащую текст, за которым следует символ комментария, вторым является текст в строке, предшествующей символу комментария, а третье представляет всю строку без символа комментария. Для строки, в начале которой содержится комментарий, элементу rm_so
во втором и третьем элементе из массива pmatch[]
присвоено значение -1
. Для строки, в начале которой содержится комментарий, значение -1
присваивается первому и второму элементу; для строки, не содержащей символы комментария, второму и третьему элементу присваивается значение -1
.
Каждый раз после завершения работы с компилированным регулярным выражением его необходимо освободить, чтобы избежать утечек памяти. Для освобождения памяти необходимо использовать функцию regfree()
, но не free()
:
#include <regex.h>
void regfree(regex_t *preg);
В стандарте POSIX четко не сказано, следует ли использовать функцию regfree()
каждый раз при вызове функции regcomp()
, или же только после того, как вы в последний раз вызывали функцию regcomp()
в одной структуре regex_t
. Таким образом, чтобы избежать утечек памяти, в промежутках между использованием структур regex_t
необходимо вызывать функцию regfree()
.
Всякий раз когда функция regcomp()
или regex()
возвращает ненулевой результат, функция regerror()
может предоставить подробное сообщение, в котором будет указано, в чем состоит ошибка. Она записывает по возможности все сообщение об ошибке в буфер и возвращает размер всего сообщения. Поскольку вы заранее не знаете, какой размер будет иметь сообщение, то сначала вам необходимо узнать его размер, а затем распределить и использовать буфер, как показано в следующем далее примере кода. Поскольку этот вариант обработки ошибок быстро становится устаревшим, и вам придется включать его как минимум дважды (один раз после функции regcomp()
и один раз после функции regex()
), мы советуем вам написать код собственной оболочки функции regerror()
, как показано в строке 10 из листинга math.с
.
23.2.3. Простая утилита grep
grep
является популярной утилитой, определенной в стандарте POSIX, которая предлагает возможности поиска регулярного выражения в текстовых файлах. Ниже показана простая (не соответствующая стандарту POSIX) версия утилиты grep
, реализованная с помощью функций стандартного регулярного выражения.