Analizar pares de claves de valor cuando la llave no es único

votos
0

Mi entrada son la clave múltiple, pares de valores, por ejemplo:

A=1, B=2, C=3, ..., A=4

Quiero analizar la entrada en el siguiente tipo:

 std::map< char, std::vector< int > > m

Los valores de claves iguales figurarán como anexo en el vector. Lo que la salida analizada debe ser igual a:

m['A']={1,4};
m['B']={2};
m['C']={3};

¿Cuál es la solución más simple usando 'impulso :: :: espíritu qi'?

Publicado el 27/11/2018 a las 16:49
fuente por usuario
En otros idiomas...                            


1 respuestas

votos
0

Esta es una manera de hacerlo:

#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/at_c.hpp>
#include <iostream>
#include <utility>
#include <string>
#include <vector>
#include <map>

namespace qi = boost::spirit::qi;
namespace fusion = boost::fusion;

int main()
{
    std::string str = "A=1, B=2, C=3, A=4";

    std::map< char, std::vector< int > > m;
    auto inserter = [&m](fusion::vector< char, int > const& parsed,
        qi::unused_type, qi::unused_type)
    {
        m[fusion::at_c< 0 >(parsed)].push_back(fusion::at_c< 1 >(parsed));
    };

    auto it = str.begin(), end = str.end();
    bool res = qi::phrase_parse(it, end,
        ((qi::char_ >> '=' >> qi::int_)[inserter]) % ',',
        qi::space);

    if (res && it == end)
        std::cout << "Parsing complete" << std::endl;
    else
        std::cout << "Parsing incomplete" << std::endl;

    for (auto const& elem : m)
    {
        std::cout << "m['" << elem.first << "'] = {";
        for (auto value : elem.second)
            std::cout << " " << value;
        std::cout << " }" << std::endl;
    }

    return 0;
}

Algunos comentarios acerca de la aplicación:

  1. qi::phrase_parsees un algoritmo de Boost.Spirit que toma un par de iteradores, un analizador y un analizador de salto, y ejecuta los programas de análisis en la entrada denotado por los iteradores. En el proceso, se actualiza el iterador comenzando ( iten este ejemplo) de manera que apunte al final de la entrada consumida a su regreso. El devuelto resvalor indica si los analizadores han tenido éxito (es decir, la entrada consumida se pudo analizar con éxito). Hay otras formas de qi::phrase_parseque los atributos de permitir la extracción (que es el de datos analizados, en términos de Boost.Spirit) pero no estamos utilizando atributos aquí porque usted tiene un requisito peculiar de la estructura del contenedor resultante.

  2. El analizador de salto se utiliza para omitir porciones de la entrada entre los elementos del analizador principal. En este caso, qi::spacesignifica que los caracteres de espacio en blanco serán ignorados en la entrada, de modo que por ejemplo, "A = 1" y "A = 1" puede tanto ser analizado de manera similar. Existe qi::parsefamilia de algoritmos que no tienen un programa de análisis de salto y por lo tanto requieren el analizador principal para manejar todas las entradas y sin saltos.

  3. La (qi::char_ >> '=' >> qi::int_)parte del analizador principal coincide con un solo carácter , seguido por el signo de igual carácter, seguido de un entero con signo . El signo igual se expresa como un literal (es decir, es equivalente a la qi::lit('=')parser), lo que significa que sólo coincide con la entrada, pero no da como resultado un conjunto de datos analizados. Por lo tanto el resultado de este analizador es un atributo que es una secuencia de dos elementos - un carácter y un entero.

  4. La % ','parte del analizador es un analizador de la lista , que analiza cualquier número de piezas de entrada descrita por el analizador de la izquierda (que es el analizador descrito anteriormente), separados por las piezas descritas por el analizador a la derecha (es decir, con caracteres comas en nuestro caso). Al igual que antes, el carácter coma es un programa de análisis literal, por lo que no produce salida.

  5. La [inserter]pieza es una acción semántica , que es una función que se llama por el intérprete cada vez que coincide con una porción de la cadena de entrada. El analizador pasa toda su producción se analiza como el primer argumento de esta función. En nuestro caso la acción semántica está unido al analizador descrito en la bala # 3, lo que significa una secuencia de un personaje y se pasa un entero. Boost.Spirit utiliza un fusion::vectorceder esos datos. Los otros dos argumentos de la acción semántica no se utilizan en este ejemplo y pueden ser ignorados.

  6. La inserterfunción en este ejemplo es una función lambda, pero podría ser cualquier otro tipo de objeto de función, incluyendo una función regular, una función que genera std::bind, etc. La parte importante es que tiene la signatura especificada y que el tipo de su primera argumento es compatible con el atributo del analizador, a la que se adjunta como una acción semántica. Por lo tanto, si tuviéramos un analizador diferente en bala # 3, este argumento tendría que ser cambiado en consecuencia.

  7. fusion::at_c< N >()en el inserterobtiene el elemento del vector en el índice N. Es muy similar a std::get< N >()cuando se aplica a std::tuple.

Respondida el 30/11/2018 a las 00:25
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more