В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13 |
Средства обработки структурированных данных
На уровне функций работа с регулярными выражениями поддержана семейством 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, пробуя различные варианты, в том числе некорректные.