Регулярные выражения могут быть чрезвычайно полезны при решении множества задач. Пару лет назад в этом блоге рассматривались регулярные выражения 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 ] = ‘ ‘ ;
printQueryString ( & buf [ qstart ] ) ;
Заметьте, что последняя 1/3 буфера mvector используется процедурой pcre_exec для хранения временных данных. Это следует учитывать при расчете размера буфера. Например, буфера из 4-х элементов будет недостаточно, если в вашем регулярном выражении используется одна пара скобочек. На мой взгляд, это далеко не самый удачный API. Однако на практике можно не париться, и просто делать буфер побольше.
Собственно, это все! Полноценный пример использования libpcre вы найдете в этом репозитории . По крайней мере, он там был в районе коммита ed77154d. В будущем ситуация может немного измениться.
А какую библиотеку для работы с регулярными выражениями вы используете при программировании на C/C++?
Дополнение: Пример кэширования регулярных выражений можно найти в заметке Практическая польза классов-синглтонов с примером на C++ .