Expressões regulares em C++ com exemplos: na prática
\n\nExpressões regulares (regex) são uma ferramenta poderosa para processamento de texto, permitindo buscar, substituir e validar strings com padrões complexos. Em C++, o suporte a expressões regulares foi introduzido no padrão C++11 através da biblioteca <regex>. Neste artigo, vamos explorar como usar std::regex na prática: desde validações simples até extração de dados e substituição de texto.
O material será útil tanto para iniciantes que estão conhecendo C++, quanto para desenvolvedores experientes que desejam revisar o assunto. Abordaremos as principais funções: std::regex_match, std::regex_search e std::regex_replace, além do trabalho com grupos de captura.
Componentes principais da biblioteca <regex>
\n\nAntes de passar aos exemplos, vamos entender as principais classes e funções:
\n\n- \n
- std::regex — classe que representa a própria expressão regular (padrão). É criada a partir de uma string com o padrão e uma flag opcional de gramática (padrão ECMAScript). \n
- std::smatch — contêiner para armazenar resultados de busca (para strings do tipo
std::string). O análogo éstd::cmatchpara strings C. \n - std::regex_match — verifica se toda a string corresponde exatamente ao padrão. \n
- std::regex_search — busca uma substring que corresponda ao padrão em qualquer parte da string. \n
- std::regex_replace — substitui todas as correspondências do padrão por uma string especificada (com suporte a referências reversas). \n
Todas as funções aceitam flags para controlar o comportamento (por exemplo, std::regex_constants::icase para busca case-insensitive).
Exemplo 1: Validando uma string com o padrão (std::regex_match)
\n\nA tarefa mais simples é verificar se uma string corresponde a um formato específico. Por exemplo, vamos verificar se a string é um endereço de email válido (versão simplificada):
\n\n#include <iostream>\n#include <regex>\n#include <string>\n\nint main() {\n std::string email = "user@example.com";\n // Padrão para validar email (simplificado)\n std::regex pattern(R"([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})");\n\n if (std::regex_match(email, pattern)) {\n std::cout << "Email válido." << std::endl;\n } else {\n std::cout << "Email inválido." << std::endl;\n }\n\n // Testando um email inválido\n std::string bad_email = "user@.com";\n if (std::regex_match(bad_email, pattern)) {\n std::cout << "Email válido." << std::endl;\n } else {\n std::cout << "Email inválido." << std::endl;\n }\n\n return 0;\n}\n\nSaída:
\nEmail válido.\nEmail inválido.\n\nExplicação:
\n- \n
- Usamos um literal de string bruta
R"(...)"para evitar escapar barras invertidas. \n - A função
std::regex_matchretornatrueapenas se toda a string corresponder exatamente ao padrão. \n - O padrão
[a-zA-Z0-9._%+-]+significa "um ou mais caracteres do conjunto especificado". \n
Exemplo 2: Buscando substring e extraindo dados (std::regex_search)
\n\nFrequentemente, não basta apenas validar; é necessário encontrar todas as ocorrências do padrão e extrair partes da string. Para isso, usamos std::regex_search em um loop. No exemplo a seguir, encontraremos todos os números de telefone no formato +7-XXX-XXX-XX-XX em um texto e extrairemos o código da operadora:
#include <iostream>\n#include <regex>\n#include <string>\n\nint main() {\n std::string text = "Contatos: +7-495-123-45-67 e +7-916-987-65-43. Número adicional: +7-495-111-22-33.";\n // Padrão: +7-código(3 dígitos)-... (grupos de captura para código e restante)\n std::rege