Регулярные выражения являются формой сопоставления шаблонов, которые часто используются в обработке текста; многие пользователи будут знакомы с утилитами Unix grep, sed и awk, а также языком программирования Perl, каждый из которых широко использует регулярные выражения. Традиционно пользователи C++ были ограничены POSIX C API для манипулирования регулярными выражениями. Regex действительно предоставляет эти API, они не представляют собой лучший способ использования библиотеки. Например, рост. Regex может справляться с широкими строками символов или искать и заменять операции (аналогично Sed или Perl), что традиционные библиотеки C не могут сделать.
Класс<basic_regex
>является ключевым классом в этой библиотеке; он представляет собой «машиночитаемое» регулярное выражение и очень тесно смоделировано на<std::basic_string
>, подумайте о нем как о строке плюс фактическая государственная машина, требуемая алгоритмами регулярного выражения. Как и<std::basic_string
>, есть два типа, которые почти всегда являются средством, с помощью которого этот класс упоминается:
namespace boost{
template <class charT,
class traits = regex_traits<charT> >
class basic_regex;
typedef basic_regex<char> regex;
typedef basic_regex<wchar_t> wregex;
}
Чтобы увидеть, как можно использовать эту библиотеку, представьте, что мы пишем приложение для обработки кредитных карт. Номера кредитных карт обычно представляют собой строку из 16 цифр, разделенную на группы из 4 цифр и разделенную пространством или дефисом. Прежде чем хранить номер кредитной карты в базе данных (не обязательно то, что по достоинству оценят ваши клиенты!), мы можем проверить, что номер находится в правильном формате. Чтобы соответствовать любой цифре, мы могли бы использовать обычное выражение [0-9], однако диапазоны символов, подобные этому, на самом деле зависят от местоположения. Вместо этого мы должны использовать стандартную форму POSIX или Boost. Regex и Perl сокращение для этого \d (обратите внимание, что многие старые библиотеки, как правило, были жестко закодированы в C-локале, следовательно, это не было проблемой для них). Это дает нам следующее регулярное выражение для проверки форматов номеров кредитных карт:
(\d{4}[- ]){3}\d{4}
Здесь скобки действуют для группирования (и маркировки для будущей ссылки) подвыражений, а {4} означает «повторять ровно 4 раза». Это пример расширенного синтаксиса регулярных выражений, используемого Perl, awk и egrep. Повышаю. Regex также поддерживает старый «базовый» синтаксис, используемый sed и grep, но это, как правило, менее полезно, если у вас уже нет некоторых основных регулярных выражений, которые вам нужно повторно использовать.
Теперь давайте возьмем это выражение и поместим его в код C++ для проверки формата номера кредитной карты:
bool validate_card_format(const std::string& s)
{
static const boost::regex e("(\\d{4}[- ]){3}\\d{4}");
return regex_match(s, e);
}
Обратите внимание, как мы должны были добавить некоторые дополнительные выходы к выражению: помните, что выход один раз виден компилятором C++, прежде чем он будет виден движком регулярного выражения, следовательно, выходы в регулярных выражениях должны быть удвоены при встраивании их в код C / C++. Также обратите внимание, что все примеры предполагают, что ваш компилятор поддерживает поиск, зависящий от аргументов, если ваш не поддерживает (например, VC6), то вам придется добавить некоторые префиксы<boost::
>к некоторым вызовам функции в примерах.
Те из вас, кто знаком с обработкой кредитных карт, поймут, что, хотя используемый выше формат подходит для считываемых человеком номеров карт, он не представляет формат, требуемый системами онлайн-кредитных карт; они требуют числа в виде строки из 16 (или, возможно, 15) цифр, без каких-либо промежуточных пространств. Нам нужно средство для легкой конвертации между двумя форматами, и именно здесь появляется поиск и замена. Те, кто знаком с утилитами sed и Perl, уже будут здесь впереди; нам нужны две струны — одна регулярное выражение — другая «форматная струна», дающая описание текста для замены матча. В Росте. Regex этот поиск и замена операции выполняется с помощью алгоритма<regex_replace
>, для примера с нашей кредитной картой мы можем написать два таких алгоритма, чтобы обеспечить преобразование формата:
const boost::regex e("\\A(\\d{3,4})[- ]?(\\d{4})[- ]?(\\d{4})[- ]?(\\d{4})\\z");
const std::string machine_format("\\1\\2\\3\\4");
const std::string human_format("\\1-\\2-\\3-\\4");
std::string machine_readable_card_number(const std::string s)
{
return regex_replace(s, e, machine_format, boost::match_default | boost::format_sed);
}
std::string human_readable_card_number(const std::string s)
{
return regex_replace(s, e, human_format, boost::match_default | boost::format_sed);
}
Здесь мы использовали отмеченные суб-выражения в обычном выражении, чтобы разделить четыре части номера карты как отдельные поля, строка формата затем использует синтаксис, похожий на сед, чтобы заменить соответствующий текст переформатированной версией.
В приведенных выше примерах мы непосредственно не манипулировали результатами матча с регулярным выражением, однако в целом результат матча содержит ряд матчей с подвыражением в дополнение к общему матчу. Когда библиотека должна сообщать о совпадении регулярных выражений, она делает это, используя экземпляр класса.<match_results
>, как и раньше существуют типдефы этого класса для наиболее распространенных случаев:
namespace boost{
typedef match_results<const char*> cmatch;
typedef match_results<const wchar_t*> wcmatch;
typedef match_results<std::string::const_iterator> smatch;
typedef match_results<std::wstring::const_iterator> wsmatch;
}
Алгоритмы<regex_search
>и<regex_match
>используют<match_results
>для сообщения о том, что совпадало; разница между этими алгоритмами заключается в том, что<regex_match
>найдут только совпадения, которые потребляютвсевходного текста, где как<regex_search
>будет искать совпадение в любом месте в пределах согласованного текста.
Обратите внимание, что эти алгоритмы не ограничиваются поиском обычных C-струн, можно искать любой двунаправленный тип итератора, что позволяет легко искать практически любые данные.
Для операций поиска и замены, в дополнение к алгоритму<regex_replace
>, который мы уже видели, класс<match_results
>имеет<format
>элемент, который принимает результат соответствия и строку формата и производит новую строку, объединяя их.
Для итерации во всех случаях выражения в тексте существуют два типа итераторов:<regex_iterator
>перечислит найденные объекты<match_results
>, а<regex_token_iterator
>перечислит ряд строк (аналогично операциям разделения стиля perl).
Для тех, кто не любит шаблоны, существует класс обертки высокого уровня<RegEx
>, который является инкапсуляцией кода шаблона нижнего уровня — он обеспечивает упрощенный интерфейс для тех, кому не нужна полная мощность библиотеки, и поддерживает только узкие символы, а также «расширенный» синтаксис регулярного выражения. Этот класс теперь обесценивается, поскольку он не является частью стандартного предложения библиотеки C++.
Функции POSIX API:<regcomp
>,<regexec
>,<regfree
>и [regerr] доступны как в узких версиях, так и в версиях Unicode и предназначены для тех, кто нуждается в совместимости с этими API.
Наконец, обратите внимание, что библиотека теперь имеетподдержку локализации времени выполненияи распознает полный синтаксис регулярных выражений POSIX, включая расширенные функции, такие как элементы многохарактерного сопоставления и классы эквивалентности, а также обеспечивает совместимость с другими библиотеками регулярных выражений, включая пакеты регекса GNU и BSD4, PCRE и Perl 5.