libpcre/

Регулярные выражения могут быть чрезвычайно полезны при решении множества задач. Пару лет назад в этом блоге рассматривались регулярные выражения 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} )

Пример компиляции регулярного выражения:

#include <pcre.h>

/* … */

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 , предназначен для освобождения ресурсов при выходе из скоупа:

#include <defer.h>

/* … */

defer ( pcre_free ( req_re ) ) ;

Для сопоставления строки с регулярным выражением предназначена процедура pcre_exec:

int mvector [ 32 ] ;

/* … */

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 qstart = mvector [ 4 ] ;
int qend = mvector [ 5 ] ;
buf [ qend ] = ;
printQueryString ( & buf [ qstart ] ) ;

Заметьте, что последняя 1/3 буфера mvector используется процедурой pcre_exec для хранения временных данных. Это следует учитывать при расчете размера буфера. Например, буфера из 4-х элементов будет недостаточно, если в вашем регулярном выражении используется одна пара скобочек. На мой взгляд, это далеко не самый удачный API. Однако на практике можно не париться, и просто делать буфер побольше.

Собственно, это все! Полноценный пример использования libpcre вы найдете в этом репозитории . По крайней мере, он там был в районе коммита ed77154d. В будущем ситуация может немного измениться.

А какую библиотеку для работы с регулярными выражениями вы используете при программировании на C/C++?

Дополнение: Пример кэширования регулярных выражений можно найти в заметке Практическая польза классов-синглтонов с примером на C++ .

EnglishRussianUkrainian