Expresiones regulares en C++ con ejemplos: en la práctica
\n\nLas expresiones regulares (regex) son una herramienta poderosa para el procesamiento de texto, que permite buscar, reemplazar y validar cadenas según patrones complejos. En C++, el soporte para expresiones regulares apareció en el estándar C++11 a través de la biblioteca <regex>. En este artículo, analizaremos cómo usar std::regex en la práctica: desde validaciones simples hasta extracción de datos y reemplazo de texto.
El material será útil tanto para principiantes que recién se familiarizan con C++, como para desarrolladores experimentados que deseen refrescar sus conocimientos. Revisaremos las funciones clave: std::regex_match, std::regex_search y std::regex_replace, así como el trabajo con grupos de captura.
Componentes principales de la biblioteca <regex>
\n\nAntes de pasar a los ejemplos, comprendamos las clases y funciones principales:
\n\n- \n
- std::regex — clase que representa la expresión regular en sí (patrón). Se crea a partir de una cadena con el patrón y una bandera de gramática opcional (por defecto ECMAScript). \n
- std::smatch — contenedor para almacenar los resultados de la búsqueda (para cadenas de tipo
std::string). Su análogo esstd::cmatchpara cadenas C. \n - std::regex_match — verifica si toda la cadena coincide completamente con el patrón. \n
- std::regex_search — busca una subcadena que coincida con el patrón en cualquier parte de la cadena. \n
- std::regex_replace — reemplaza todas las coincidencias con el patrón por una cadena especificada (con soporte para referencias inversas). \n
Todas las funciones aceptan banderas para controlar el comportamiento (por ejemplo, std::regex_constants::icase para búsqueda sin distinción de mayúsculas y minúsculas).
Ejemplo 1: Validación de cadena contra un patrón (std::regex_match)
\n\nLa tarea más simple es verificar si una cadena cumple con un formato dado. Por ejemplo, comprobemos si una cadena es una dirección de correo electrónico válida (versión simplificada):
\n\n#include <iostream>\n#include <regex>\n#include <string>\n\nint main() {\n std::string email = "user@example.com";\n // Patrón 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 // Validación de un email incorrecto\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\nSalida:
\nEmail válido.\nEmail inválido.\n\nExplicación:
\n- \n
- Usamos un literal de cadena sin procesar
R"(...)"para no tener que escapar las barras invertidas. \n - La función
std::regex_matchdevuelvetruesolo si toda la cadena coincide completamente con el patrón. \n - El patrón
[a-zA-Z0-9._%+-]+significa "uno o más caracteres del conjunto especificado". \n
Ejemplo 2: Búsqueda de subcadenas y extracción de datos (std::regex_search)
\n\nA menudo no solo se necesita validar, sino encontrar todas las ocurrencias de un patrón y extraer partes de la cadena. Para esto se usa std::regex_search en un bucle. En el siguiente ejemplo, encontraremos todos los números de teléfono en el formato +7-XXX-XXX-XX-XX en un texto y extraeremos el código de operador:
#include <iostream>\n#include <regex>\n#include <string>\n\nint main() {\n std::string text = "Contactos: +7-495-123-45-67 y +7-916-987-65-43. Número adicional: +7-495-111-22-33.";\n // Patrón: +7-código(3 dígitos)-... (grupos de captura para el código y el resto)\n std::rege