Регулярные выражения в С++: использование Boost::Regex
В этой заметке я рассмотрю такую достаточно популярную тему, как использование регулярных выражений. Причем, рассматривать я буду применительно к C++ с использованием библиотеки Boost, которая содержит замечательные средства для их поддержки.
Используемый синтаксис реглярных выражений совпадает с широко известным PCRE (Perl-Compatible Regular Expressions).
Для использования библиотеки необходимо включить заголовочный файл boost/regex.hpp:
#include <boost/regex.hpp>
Сразу стоит отметить, что в отличие от многих других компонентов Boost, этот компонент содержит является скопилированным, и потому требует связывания с соответствующей библиотекой. В частности, для компилятора GCC необходимо при связывании добавлять флаг -lboost_regex.
Простейшее использование
Для того, чтобы определить регулярное выражение для дальнейшего использования, достаточно объявить переменную типа boost::regexp и передать в конструктор текст регялрного выражения. Например:
boost::regexp exp("(\\d{4}[- ]){3}\\d{4}");
Для того, чтобы обрабатывать регулярные выражения Boost предоставляет три основных функции:
- regex_match - проверка сопоставления выражения строке;
- regex_search - поиск сопоставлений выражения в строке;
- regex_replace - замена сопоставлений выражения в строке на заданную подстроку.
bool r1 = boost::regex_match( "what", exp );
bool r2 = boost::regex_search( "where", exp );
std::string r3 = boost::regex_replace( "what", exp, "to" );
Получение результатов сопоставлений
Однако, в функциях regex_match и regex_search часто требуется извлекать дополнительную информацию о сопоставлении. Для этого используются объекты типа boost::match_results<IterType>. Сам match_results является шаблоном, который в качестве аргумента принимает тип итератора для сопоставляемых символов. Однако, использовать его напрямую совсем не обязательно. Boost предоставляет 4 типа, представляющих уже параметризованные варианты match_results:
namespace boost {
typedef match_results<const char*> cmatch; // Используется при сопоставлении C-строк
typedef match_results<const wchar_t*> wcmatch; // Используется при сопоставлении С-строк в Unicode
typedef match_results<std::string::const_iterator> smatch; // Используется при сопоставлении STL-строк
typedef match_results<std::wstring::const_iterator> wsmatch; // Используется при сопоставлении STL-строк в Unicode
}
match_results содержит следующие методы и операторы для работы с результатами сопоставлений:
- size() - количество групп сопоставлений;
- suffix(), prefix() - информация о префиксе и суффиксе сопоставления;
- [i] - информация об i-й группе сопоставления.
- first - итератор, указывающий на начало группы сопоставдления;
- second - итератор, указывающий на конец группы сопоставдления;
- matched - булево поле, равное true если группа была сопоставлена.
boost::cmatch m;
if ( boost::regexp_match( "what", m, exp ) ) {
int sz = m.size(); // Количество групп сопоставления
for ( int i = 0; i < sz; ++ i )
std::cout << std::string( m[i].first, m[i].second ) << std::endl;
}
while ( boost::regexp_search( "waht", m, exp ) ) {
...
}
Примеры
В качестве первого примера, рассмотрим функцию на C++, которая проверяет, может ли заданная строка являться корректным адресом электронной почты:
#include <string>
#include <boost/regex.hpp>
bool can_be_email( const std::string & s ) {
static const boost::regex e("[a-zA-Z0-9_\\.]+@([a-zA-Z0-9]+\\.)+[a-zA-Z]{2,4}");
return boost::regex_match( s, e );
}
Второй пример: извлечение из e-mail имени ящика и домена:
#include <string>
#include <stdexcept>
#include <boost/regex.hpp>
std::pair<std::string,std::string> split_email( const std::string & s ) {
static const boost::regex e("([a-zA-Z0-9_\\.]+)@(([a-zA-Z0-9]+\\.)+[a-zA-Z]{2,4})");
boost::smatch m;
if ( boost::regex_match( s, m, e ) ) {
return std::make_pair( std::string( m[1].first, m[1].second ), std::string( m[2].first, m[2].second ) );
} else {
throw std::runtime_error( "Bad email" );
}
}
