¿Cómo capturar grupos de 0-2 en expresiones regulares de C ++ e imprimirlos?
Fui al enfoque de análisis personalizado de Good'ol ya que me quedé atascado con la expresión regular. No resultó ser tan malo, ya que los contenidos del archivo se pueden tokenizar con bastante claridad y los tokens se pueden analizar en un bucle con unmuy máquina de estado simple. Aquellos que quieran verificar, hay un fragmento de código que hace esto con el rango para, iteradores ifstream y tokenizer de flujo personalizado en mi otra pregunta en Stackoverflowaquí. Estas técnicas disminuyen considerablemente la complejidad de hacer un analizador personalizado.
Me gustaría tokenizar el contenido del archivo en la primera parte en la captura de grupos de dos y luego línea por línea. Me gusta una solución semi-funcional, pero me gustaría aprender a mejorar esto. Es decir, sin "procesamiento adicional" para compensar mi falta de conocimiento con los grupos de captura. A continuación algunos preliminares y al final una pregunta más exacta (la línea
const std::regex expression("([^:]+?)(^:|$)");
... es el que me gustaría preguntar en combinación con el procesamiento de los resultados.
Los archivos que básicamente se definen así:
definition_literal : value_literal
definition_literal : value_literal
definition_literal : value_literal
definition_literal : value_literal
HOW TO INTERPRET THE FOLLOWING SECTION OF ROWS
[DATA ROW 1]
[DATA ROW 2]
...
[DATA ROW n]
Donde cada una de las filas de datos consiste en un cierto número de enteros o números de punto flotante separados por espacios en blanco. Cada fila tiene tantos números como los demás (por ejemplo, cada fila podría tener cuatro enteros). Entonces, la "sección de interpretación" básicamente dice este formato en texto plano en una fila.
Tengo una solución casi funcional que lee archivos como este:
int main()
{
std::ifstream file("xyz", std::ios_base::in);
if(file.good())
{
std::stringstream file_memory_buffer;
file_memory_buffer << file.rdbuf();
std::string str = file_memory_buffer.str();
file.close();
const std::regex expression("([^:]+?)(^:|$)");
std::smatch result;
const std::sregex_token_iterator end;
for(std::sregex_token_iterator i(str.begin(), str.end(), expression); i != end; ++i)
{
std::cout << (*i) << std::endl;
}
}
return EXIT_SUCCESS;
}
Con la expresión regular definidaexpression
, ahora imprime el<value>
partes del archivo de definición, luego la parte de interpretación y luego las filas de datos una por una. Si cambio la expresión regular a
"([^:]+?)(:|$)"
... imprime todas las líneas tokenizadas en grupos de uno, casi como me gustaría, pero ¿cómo tokenize la primera parte en grupos de dos y el resto línea por línea?
Cualquier puntero, código, explicaciones son realmente bienvenidos. Gracias.
EDITAR:Como se señaló aTom Kerr ya, pero algunos puntos adicionales, esto también es un ensayo, o codificación de kata si así lo desea, no para escribir un analizador personalizado, sino para ver si podría (o podríamos :-) - lograr esto con regex. Sé que la expresión regular no es lo más eficiente que se puede hacer aquí, pero no importa.
Lo que espero tener es algo así como una lista de tuplas de información de encabezado (tupla de tamaño 2), luego la línea INTERPRET (tupla de tamaño 1), que podría usar para elegir una función sobre qué hacer con los datos Líneas (tupla de tamaño 1).
Sí, la línea "CÓMO INTERPRETAR" está contenida en un conjunto de cadenas bien definidas y pude leer línea por línea desde el principio, dividiendo cadenas a lo largo del camino, hasta que se cumpla una de las líneas de INTERPRET. Esta solución no es el método más eficiente, lo sé, pero es más como codificar kata para que yo pueda escribir algo más que analizadores de clientes (y es bastante tiempo que escribí en C ++ la última vez, así que esto también está ensayando) ).
Editar 2He logrado obtener acceso a las tuplas (en el contexto de esta pregunta) cambiando el tipo de iterador, por lo que
const std::sregex_iterator end;
for(std::sregex_iterator i(str.begin(), str.end(), expression); i != end; ++i)
{
std::cout << "0: " << (*i)[0] << std::endl;
std::cout << "1: " << (*i)[1] << std::endl;
std::cout << "2: " << (*i)[2] << std::endl;
std::cout << "***" << std::endl;
}
Aunque esto aún está muy lejos de lo que me gustaría tener, hay algo mal con la expresión regular que trato de usar. En cualquier caso, este nuevo hallazgo, otro tipo de iterador, también ayuda.