Boost :: Spirit :: QI parser: индекс проанализированного элемента

Можно ли (используя Boost :: Spirit :: QI) проанализировать числа из строки, разделенной запятыми, чтобы я получил индекс каждого проанализированного числа?

Предположим, у меня есть строка "23,123,65,1" и я хочу вставить каждое из этих чисел в матрицу в заданных местах (0, 1, 2, 3). Один из способов сделать это — проанализировать числа в std :: 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++;
});
}

Было бы здорово, если бы у парсера был успешный обратный вызов, который принимает лямбда-функцию или аналогичную функцию.

5

Решение

Есть ряд подходов.

  • Вместо этого я обычно рекомендую хорошо продуманные repeat(n) выражения с прямым воздействием атрибуты контейнера (лайк vector<vector<double> >).

  • Что ты казаться искать — это семантические действия с государством. (Это обычная практика от lex / yacc).

Я рассматриваю эти подходы в трех полных демонстрациях ниже (1., 2. и 3.)

  • Продвинутая техника использует точки настройки позволить Духу напрямую относиться к вашему Matrix введите в качестве атрибута контейнера и переопределите логику вставки для него, используя spirit::traits, Для этого подхода я ссылаюсь на этот ответ: передать атрибут дочернего правила в духе буста.

С помощью унаследованные атрибуты

Вот относительно простой подход:

  1. Разбор непосредственно в vector<vector<double> > (полный код онлайн)

    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) ];
    

    Использование:

    if (qi::phrase_parse(f,l,parser(10, 4),qi::blank, m))
    std::cout << "Wokay\n";
    else
    std::cerr << "Uhoh\n";
    
  2. Точно так же, но адаптируя Matrix структура (полный код здесь)

    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))
    

    использование

    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";
    

Использование семантических действий / qi :: locals

3. Это больше работы, но потенциально более гибкий. Вы бы определили полиморфный вызываемый тип для вставки значения в данную ячейку:

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)

Последняя строка делает это phoenix ленивая функция, так что вы можете использовать ее без странного синтаксиса привязки в ваших семантических действиях:

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*/])
;

Полный код, опять же жить на liveworkspace.org

12

Другие решения

Других решений пока нет …