Опубликован: 15.06.2004 | Доступ: свободный | Студентов: 2557 / 712 | Оценка: 4.35 / 3.96 | Длительность: 27:47:00
ISBN: 978-5-9556-0011-6
Лекция 6:

Средства обработки структурированных данных

На уровне функций работа с регулярными выражениями поддержана семейством regex (см. листинг 6.34).

#include <regex.h>
int regcomp (regex_t *restrict preg, 
    const char *restrict pattern, int cflags);
int regexec (const regex_t *restrict preg, 
    const char *restrict string, 
    size_t nmatch, regmatch_t 
	pmatch [restrict], int eflags);
void regfree (regex_t *preg);
size_t regerror (int errcode, const regex_t
    *restrict preg, char *restrict errbuf, 
	size_t errbuf_size);
Листинг 6.34. Описание функций семейства regex().

Первый член этого семейства, функция regcomp(), компилирует регулярное выражение, заданное аргументом pattern, и помещает результат компиляции в структуру типа regex_t, на которую указывает аргумент preg. Эта структура, описанная в заголовочном файле <regex.h>, должна содержать про крайней мере поле

size_t re_nsub; 
/* Число заключенных в скобки подвыражений */

Третий аргумент функции regcomp(), cflags, задается как побитное ИЛИ следующих флагов:

REG_EXTENDED

Использовать расширенные регулярные выражения (подразумеваемый тип регулярных выражений - базовые ).

REG_ICASE

При сопоставлении не различать большие и малые буквы.

REG_NOSUB

В regexec() сообщать только об успехе/неудаче сопоставления (и не устанавливать значения поля   re_nsub структуры regex_t ).

REG_NEWLINE

Изменить трактовку переводов строк (мы не будем на этом останавливаться).

Функция regexec() сопоставляет цепочку символов   string со скомпилированным шаблоном, заданным аргументом preg. При успешном выполнении результат равен нулю; в противном случае возвращается ненулевое значение, свидетельствующее о неудаче сопоставления или ошибке. Аргумент eflags - побитное ИЛИ флагов REG_NOTBOL и REG_NOTEOL - определяет, являются ли границы цепочки границами строки, что важно для обработки фиксаторов ^ и $. Если значение аргумента nmatch равно нулю или при вызове regcomp() был задан флаг REG_NOSUB, аргумент pmatch функции regexec() игнорируется. В противном случае он должен указывать на массив не менее чем из nmatch элементов, который будет заполнен смещениями подцепочек, сопоставленных с заключенными в скобки подвыражениями шаблона ( pmatch [0] соответствует всему регулярному выражению, в неиспользуемые элементы помещается -1).

Структурный тип regmatch_t должен включать по крайней мере следующие поля:

regoff_t rm_so; 
/* Смещение в байтах начала подцепочки 
от начала цепочки */

regoff_t rm_eo; 
/* Смещение в байтах первого символа за 
концом подцепочки от начала цепочки */

Тип regoff_t определяется как целое со знаком, способное вместить любое значение типов off_t и ssize_t.

Функция regfree() освобождает память, запрошенную вызовом regcomp() с тем же значением аргумента preg, которое после этого нельзя использовать как указатель на скомпилированное регулярное выражение.

В файле <regex.h> определены константы, возвращаемые функциями семейства regex() в случае ошибки. Например, значение REG_NOMATCH возвращается функцией regexec() при неудаче сопоставления, REG_BADPAT обозначает некорректное регулярное выражение, REG_ESPACE - нехватку памяти и т.д. Функция regerror() отображает эти константы в неспецифицируемые стандартом цепочки печатных символов и помещает их в буфер errbuf. Приложение, вызывая regerror(), должно передать в качестве аргумента errcode последнее ненулевое значение, возвращенное функциями regcomp() или regexec() с заданным значением аргумента preg.

Приведем пример использования функций семейства regex() (см. листинг 6.35). Обратим внимание на задание флага REG_NOTBOL при повторных обращениях к regexec().

#include <stdio.h>
#include <limits.h>
#include <regex.h>

/* Программа ищет все вхождения заданного шаблона во всех входных строках */
/* и выводит успешно сопоставленные подцепочки */

#define PATTERN "[A-Za-z][A-Za-z0-9]{0,31}"

int main (void) {
   char line [LINE_MAX];     /* Буфер для входных строк */
   char *pline;              /* Указатель на начало сопоставляемой части строки */
   regex_t cere;             /* Скомпилированное расширенное регулярное выражение */
   regmatch_t pm;            /* Структура для запоминания границ сопоставленной подцепочки */
   int reerrcode;            /* Код ошибки от regcomp или regexec */
   char reerrbuf [LINE_MAX]; /* Буфер для строк с сообщениями об ошибках */
   int i;

   if ((reerrcode = regcomp (&cere, PATTERN, REG_EXTENDED)) != 0) {
        (void) regerror (reerrcode, &cere, reerrbuf, sizeof (reerrbuf));
        fputs (reerrbuf, stderr);
        fputc ('\n', stderr);
        regfree (&cere);
        return (reerrcode);
   }

   fputs ("Вводите строки, сопоставляемые с шаблоном " PATTERN "\n", stdout);
   while (fgets (line, sizeof (line), stdin) != NULL) {
   /* Произведем первое сопоставление с прочитанной строкой. */
   /* Оно отличается от остальных при наличии в шаблоне фиксатора начала */
   reerrcode = regexec (&cere, pline = line, 1, &pm, 0);
      while (reerrcode == 0) {
          /* Повторяем, пока сопоставления с остатком строки успешны */
          fputs ("Сопоставленная подцепочка: ", stdout);
          for (pline += pm.rm_so, i = pm.rm_eo - pm.rm_so; i-- > 0; ) {
              fputc (*pline++, stdout);
          }
          fputc ('\n', stdout);
          reerrcode = regexec (&cere, pline, 1, &pm, REG_NOTBOL);
       }
    }

    regfree (&cere);
    return (ferror (stdin) || ferror (stdout));
}
Листинг 6.35. Пример использования функций семейства regex().

Читателю рекомендуется поэкспериментировать с шаблоном PATTERN, пробуя различные варианты, в том числе некорректные.

Антон Коновалов
Антон Коновалов

В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13
Планируется ли актуализация материалов данного очень полезного курса?