c++ - Boost:: Spirit:: QI parser: índice del elemento analizado
boost-spirit (1)
¿Es posible (usando Boost :: Spirit :: QI) analizar números de una cadena separada por comas para que obtenga el índice de cada número analizado?
Supongamos que tengo una cuerda "23,123,65,1"
y quiero insertar cada uno de estos números en una matriz en ubicaciones determinadas (0, 1, 2, 3). Una forma de hacerlo sería analizar los números en un std :: vector y luego copiarlos a la fila de la matriz, pero no es particularmente rápido.
Actualmente estoy usando la variante de vector:
Matrix data(10, 4);
int row = 0;
int col = 0;
std::string str = "23,123,65,1";
std::vector<double> res;
if (qi::parse(str.begin(), str.end(), qi::double_ % '','', res))
{
std::for_each(res.begin(), res.end(), [&col, &data, &row](double elem) {
data(row, col) = elem;
col++;
});
}
Sería increíble si el analizador tuviera una devolución de llamada exitosa que tomara una función lambda o una función similar.
Hay una serie de enfoques.
En su lugar, lo que normalmente recomendaría es usar expresiones de
repeat(n)
bien pensadas con atributos de contenedor directamente expuestos (comovector<vector<double> >
).Lo que parece que estás buscando son acciones semánticas con estado. (Esta es una práctica común proveniente de lex / yacc).
Trato estos enfoques en tres demostraciones completas a continuación (1., 2. y 3.)
- Una técnica avanzada consiste en utilizar puntos de personalización para permitir que Spirit trate directamente su tipo de
Matrix
como un atributo de contenedor y anule la lógica de inserción utilizandospirit::traits
. Para este enfoque, me refiero a esta respuesta: pase el atributo a la regla del niño en el impulso del espíritu .
Usando atributos heredados
Aquí hay un enfoque relativamente directo:
analizando directamente en un
vector<vector<double> >
( código completo en vivo en línea )qi::rule<It, Matrix::value_type(size_t cols), qi::blank_type> row; qi::rule<It, Matrix(size_t rows,size_t cols), qi::blank_type> matrix; row %= skip(char_(" /t,")) [ repeat(_r1) [ double_ ] ]; matrix %= eps // [ std::cout << phx::val("debug: ") << _r1 << ", " << _r2 << "/n" ] >> repeat(_r1) [ row(_r2) >> (eol|eoi) ];
Uso:
if (qi::phrase_parse(f,l,parser(10, 4),qi::blank, m)) std::cout << "Wokay/n"; else std::cerr << "Uhoh/n";
Del mismo modo, pero adaptando una estructura
Matrix
( código completo en vivo aquí )struct Matrix { Matrix(size_t rows, size_t cols) : _cells(), _rows(rows), _cols(cols) { } double & data(size_t col, size_t row) { return _cells.at(row).at(col); } const double & data(size_t col, size_t row) const { return _cells.at(row).at(col); } size_t columns() const { return _cols; } size_t rows() const { return _rows; } std::vector<std::vector<double> > _cells; size_t _rows, _cols; }; BOOST_FUSION_ADAPT_STRUCT(Matrix, (std::vector<std::vector<double> >,_cells))
Uso
Matrix m(10, 4); if (qi::phrase_parse(f,l,parser(m.rows(),m.columns()),qi::blank, m)) std::cout << "Wokay/n"; else std::cerr << "Uhoh/n";
Usando acciones semánticas / qi :: locals
3. Esto es más trabajo, pero potencialmente más flexible. Debería definir un tipo polimórfico invocable para insertar un valor en una celda determinada:
struct MatrixInsert
{
template <typename, typename, typename, typename> struct result { typedef bool type; };
template <typename Matrix, typename Row, typename Col, typename Value>
bool operator()(Matrix &m, Row& r, Col& c, Value v) const
{
if (r < m.rows() && c < m.columns())
{
m.data(r, c++) = v;
return true; // parse continues
}
return false; // fail the parse
}
};
BOOST_PHOENIX_ADAPT_CALLABLE(matrix_insert, MatrixInsert, 4)
La última línea hace de esto una función diferida del phoenix
, por lo que puedes usarla sin una sintaxis de enlace extraña en tus acciones semánticas:
qi::rule<It, Matrix(), qi::blank_type, qi::locals<size_t /*_a: row*/, size_t/*_b: col*/> > matrix;
matrix = eps [ _a = 0 /*current row*/ ]
>> (
eps [ _b = 0 /*current col*/ ]
>> double_ [ _pass = matrix_insert(_val, _a, _b, _1) ] % '',''
) % (eol [ ++_a /*next row*/])
;
El código completo es, otra vez en vivo en liveworkspace.org