Регулярные выражения в C++ с примерами: на практике
Регулярные выражения (regex) — мощный инструмент для обработки текста, позволяющий искать, заменять и проверять строки по сложным шаблонам. В C++ поддержка регулярных выражений появилась в стандарте C++11 через библиотеку <regex>. В этой статье мы разберем, как использовать std::regex на практике: от простых проверок до извлечения данных и замены текста.
Материал будет полезен как новичкам, которые только знакомятся с C++, так и опытным разработчикам, желающим освежить знания. Мы рассмотрим ключевые функции: std::regex_match, std::regex_search и std::regex_replace, а также работу с группами захвата.
Основные компоненты библиотеки <regex>
Прежде чем перейти к примерам, разберемся с основными классами и функциями:
- std::regex — класс, представляющий само регулярное выражение (шаблон). Создается из строки с шаблоном и опциональным флагом грамматики (по умолчанию ECMAScript).
- std::smatch — контейнер для хранения результатов поиска (для строк типа
std::string). Аналог —std::cmatchдля C-строк. - std::regex_match — проверяет, соответствует ли вся строка шаблону целиком.
- std::regex_search — ищет подстроку, соответствующую шаблону, в любом месте строки.
- std::regex_replace — заменяет все совпадения с шаблоном на указанную строку (с поддержкой обратных ссылок).
Все функции принимают флаги для управления поведением (например, std::regex_constants::icase для регистронезависимого поиска).
Пример 1: Проверка строки на соответствие шаблону (std::regex_match)
Самая простая задача — проверить, соответствует ли строка заданному формату. Например, проверим, является ли строка корректным email-адресом (упрощенная версия):
#include <iostream>
#include <regex>
#include <string>
int main() {
std::string email = "user@example.com";
// Шаблон для проверки email (упрощенный)
std::regex pattern(R"([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})");
if (std::regex_match(email, pattern)) {
std::cout << "Email корректен." << std::endl;
} else {
std::cout << "Email некорректен." << std::endl;
}
// Проверка на неверный email
std::string bad_email = "user@.com";
if (std::regex_match(bad_email, pattern)) {
std::cout << "Email корректен." << std::endl;
} else {
std::cout << "Email некорректен." << std::endl;
}
return 0;
}
Вывод:
Email корректен.
Email некорректен.
Пояснение:
- Мы используем сырой строковый литерал
R"(...)", чтобы не экранировать обратные слеши. - Функция
std::regex_matchвозвращаетtrue, только если вся строка полностью соответствует шаблону. - Шаблон
[a-zA-Z0-9._%+-]+означает "один или более символов из указанного набора".
Пример 2: Поиск подстроки и извлечение данных (std::regex_search)
Часто нужно не просто проверить, а найти все вхождения шаблона и извлечь части строки. Для этого используется std::regex_search в цикле. В следующем примере мы найдем все номера телефонов в формате +7-XXX-XXX-XX-XX в тексте и извлечем код оператора:
#include <iostream>
#include <regex>
#include <string>
int main() {
std::string text = "Контакты: +7-495-123-45-67 и +7-916-987-65-43. Доп. номер: +7-495-111-22-33.";
// Шаблон: +7-код(3 цифры)-... (группы захвата для кода и остального)
std::regex pattern(R"(\+7-(\d{3})-\d{3}-\d{2}-\d{2})");
std::smatch matches;
// Ищем все совпадения
auto begin = text.cbegin();
auto end = text.cend();
while (std::regex_search(begin, end, matches, pattern)) {
std::cout << "Найден номер: " << matches.str() << std::endl;
std::cout << " Код оператора: " << matches.str(1) << std::endl;
// Сдвигаем начало поиска после найденного совпадения
begin = matches.suffix().first;
}
return 0;
}
Вывод:
Найден номер: +7-495-123-45-67
Код оператора: 495
Найден номер: +7-916-987-65-43
Код оператора: 916
Найден номер: +7-495-111-22-33
Код оператора: 495
Пояснение:
- Круглые скобки
()в шаблоне создают группы захвата.matches.str(1)возвращает содержимое первой группы. - Мы используем итераторы
beginиendдля поиска в цикле. После каждого совпадения сдвигаемbeginна позицию после найденного текста. - Метод
matches.suffix()возвращает часть строки после совпадения.
Пример 3: Замена текста с использованием обратных ссылок (std::regex_replace)
Функция std::regex_replace позволяет заменить все вхождения шаблона на новую строку. В строке замены можно использовать обратные ссылки вида $1, $2 и т.д., которые ссылаются на группы захвата. Например, переформатируем телефонные