Регулярные выражения в C++: мощный инструмент для работы с текстом
Регулярные выражения (regex) — это мощнейший инструмент для поиска, извлечения и замены текстовых фрагментов по заданному шаблону. В C++ поддержка регулярных выражений появилась в стандарте C++11 и реализована в заголовочном файле <regex>. В этой статье мы подробно разберем, как использовать регулярные выражения в C++ на практических примерах.
Основные компоненты библиотеки <regex>
Библиотека <regex> включает в себя несколько ключевых классов и функций:
std::regex— класс, представляющий скомпилированное регулярное выражение.std::smatch— контейнер для хранения результатов поиска (для строк типаstd::string).std::regex_match— проверяет, соответствует ли вся строка шаблону.std::regex_search— ищет первое вхождение шаблона в строке.std::regex_replace— заменяет совпадения на указанный текст.
Рассмотрим каждый из этих компонентов на примерах.
Пример 1: Проверка соответствия строки шаблону (regex_match)
Функция std::regex_match возвращает true, если вся строка полностью соответствует регулярному выражению. Это идеально подходит для валидации данных, например, проверки 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;
}
В этом примере мы использовали сырую строку R"(...)", чтобы избежать экранирования обратных слешей. Шаблон проверяет, что строка содержит локальную часть, знак @, доменное имя и домен верхнего уровня.
Пример 2: Поиск подстроки в тексте (regex_search)
Если нужно найти первое вхождение шаблона внутри строки, используется std::regex_search. Результаты сохраняются в объекте std::smatch.
#include <iostream>
#include <regex>
#include <string>
int main() {
std::string text = "Мой номер телефона: +7 (123) 456-78-90. Позвоните мне!";
// Шаблон для поиска российского номера телефона
std::regex phone_pattern(R"(\+7\s?\(?\d{3}\)?\s?\d{3}[- ]?\d{2}[- ]?\d{2})");
std::smatch match;
if (std::regex_search(text, match, phone_pattern)) {
std::cout << "Найден номер: " << match.str() << std::endl;
std::cout << "Позиция: " << match.position() << std::endl;
} else {
std::cout << "Номер не найден." << std::endl;
}
return 0;
}
Объект match содержит не только найденную строку, но и информацию о позиции вхождения. Метод match.str() возвращает найденный фрагмент, а match.position() — индекс начала совпадения в исходной строке.
Пример 3: Замена текста с помощью regex_replace
Функция std::regex_replace заменяет все вхождения шаблона на указанную строку. Можно использовать обратные ссылки (backreferences) вида $1, $2 и т.д. для подстановки захваченных групп.
#include <iostream>
#include <regex>
#include <string>
int main() {
std::string text = "Сегодня 15.03.2024, а завтра будет 16.03.2024.";
// Шаблон для даты в формате ДД.ММ.ГГГГ
std::regex date_pattern(R"((\d{2})\.(\d{2})\.(\d{4}))");
// Замена на формат ГГГГ-ММ-ДД
std::string result = std::regex_replace(text, date_pattern, "$3-$2-$1");
std::cout << "Исходный текст: " << text << std::endl;
std::cout << "Результат: " << result << std::endl;
// Удаление всех цифр из строки
std::regex digit_pattern(R"(\d+)");
std::string clean_text = std::regex_replace(text, digit_pattern, "");
std::cout << "Текст без цифр: " << clean_text << std::endl;
return 0;
}
Обратите внимание на синтаксис обратных ссылок: $1 соответствует первой захваченной группе (день), $2 — второй (месяц), $3 — третьей (год). Это позволяет гибко переформатировать текст.
Пример 4: Итерация по всем совпадениям (regex_iterator)
Для обработки всех вхождений шаблона в строке удобно использовать итератор std::sregex_iterator. Он позволяет перебрать все совпадения последовательно.
#include <iostream>
#include <regex>
#include <string>
#include <vector>
int main() {
std::string text = "ID: 1234, ID: 5678, ID: 9012";
// Шаблон для поиска чисел после "ID: "
std::regex id_pattern(R"(ID:\s*(\d+))");
std::vector<std::string