Работа с регулярными выражениями в C/C++ при помощи библиотеки libpcre
1 июня 2017
Регулярные выражения могут быть чрезвычайно полезны при решении множества задач. Пару лет назад в этом блоге рассматривались регулярные выражения C++11 (std::regex). Однако тогда они показали себя не очень хорошо (стоит отметить, что ситуация уже могла измениться к лучшему), да и в чистом C этими регулярками не воспользуешься. Поэтому в данном посте мы познакомимся с более консервативным, зато проверенным временем и гарантированно работающим подходом, заключающимся в использовании библиотеки libpcre.
Примечание: Вас также могут заинтересовать посты, посвященные библиотекам libcurl, zlib, libpq и libpcap.
Библиотека PCRE (расшифровывается, как Perl Compatible Regular Expressions) легко добавляется к проекту, если вы используете CMake:
find_library(PCRE_LIBRARY pcre)
# ...
target_link_libraries(main ${PCRE_LIBRARY})
Пример компиляции регулярного выражения:
/* ... */
const char* error;
int erroroffset;
char req_pattern[] = "^(GET|POST) ([^ ?]+)[^ ]* HTTP/1.[01]$";
pcre* req_re = pcre_compile(req_pattern, 0,
&error, &erroroffset, nullptr);
if(req_re == nullptr)
throw std::runtime_error("PCRE compilation failed");
Скомпилированное регулярное выражение рано или поздно нужно освободить. В C/C++ на границе взаимодействия с библиотеками на чистом C для решения этой проблемы я предпочитаю использовать deferxx. Вы можете помнить эту библиотеку по заметке OpenGL: управление камерой при помощи мыши и клавиатуры. Библиотека добавляет в язык defer, который, аналогично defer в языке Go, предназначен для освобождения ресурсов при выходе из скоупа:
/* ... */
defer( pcre_free(req_re) );
Для сопоставления строки с регулярным выражением предназначена процедура pcre_exec:
/* ... */
int rc = pcre_exec(req_re, nullptr, buf, strlen(buf), 0, 0,
mvector, sizeof(mvector)/sizeof(mvector[0]));
if(rc < 0)
throw std::runtime_error("No match");
Если строка соответствует регулярному выражению, в mvector[0]
и mvector[1]
будут записаны индексы первого и последнего символа совпавшей части строки, в mvector[2]
и mvector[3]
— первое совпадение в скобочках, и так далее. Так в приведенном примере для вывода query string придется написать код вроде следующего:
int qend = mvector[5];
buf[qend] = '\0';
printQueryString(&buf[qstart]);
Заметьте, что последняя 1/3 буфера mvector используется процедурой pcre_exec для хранения временных данных. Это следует учитывать при расчете размера буфера. Например, буфера из 4-х элементов будет недостаточно, если в вашем регулярном выражении используется одна пара скобочек. На мой взгляд, это далеко не самый удачный API. Однако на практике можно не париться, и просто делать буфер побольше.
Собственно, это все! Полноценный пример использования libpcre вы найдете в этом репозитории. По крайней мере, он там был в районе коммита ed77154d. В будущем ситуация может немного измениться.
А какую библиотеку для работы с регулярными выражениями вы используете при программировании на C/C++?
Дополнение: Пример кэширования регулярных выражений можно найти в заметке Практическая польза классов-синглтонов с примером на C++.
Метки: C/C++.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.