1

ここのように単純な 2D int 配列 (空白で区切られた) を読みたいと思います:

qi::phrase_parse(b, e, +qi::int_ % qi::eol, qi::space - qi::eol, vectors)

ただし、次の 2 つの違いがあります。

  1. 区切らずに1行ずつ1D std::vectorに入れたい
  2. 2 つの行の int の量が異なる場合、これは解析エラーとして認識されます。

たとえば、独自のパーサーを作成せずに、これをワンライナーとして行うことは可能ですか? 上記のリンクと同じくらい簡単ですか?

4

1 に答える 1

3

あなたがスピリットバージョンを意味していると仮定すると(「ワンライナーとして」)、以下は要素数のチェックを追加する適応バージョンです。

より多くの制御が必要な場合 (および「後知恵」ではなく、その場で入力チェックを行う場合) は、これを行うための 3 つのアプローチを示す、私が書いた別の回答を参照することをお勧めします。

.

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/spirit/include/karma.hpp>

namespace spirit = boost::spirit;
namespace qi     = boost::spirit::qi;
namespace karma  = boost::spirit::karma;

int main()
{
    std::cin.unsetf(std::ios::skipws);
    spirit::istream_iterator b(std::cin), e;

    std::vector<std::vector<int> > vectors;

    if (qi::phrase_parse(b, e, +qi::int_ % qi::eol >> qi::eoi, qi::blank, vectors))
    {
        std::cerr << "Parse failed at '" << std::string(b,e) << "'\n";
        return 255;
    }

    // check all rows have equal amount of elements:
    const auto number_of_elements = vectors.front().size();
    for (auto& v : vectors)
        if (v.size() != number_of_elements)
            std::cerr << "Unexpected number of elements: " << v.size() << " (expected: " << number_of_elements << ")\n";

    // print the data for verification
    std::cout 
        << karma::format(karma::right_align(8)[karma::auto_] % ',' % '\n', vectors)
        << std::endl;

    return 0;
}

カルマ ビットは必要ありません (デモンストレーションのためにすべてを出力するためだけに存在します)。

アップデート

よりアクティブなエラー チェックを組み込むには、次のようにします。

int num_elements = 0;
bool ok = qi::phrase_parse(b, e, 
        (+qi::int_) [ phx::ref(num_elements) = phx::size(qi::_1) ]
     >> *(qi::eol >> qi::repeat(phx::ref(num_elements)) [ qi::int_ ])
     >> *qi::eol, 
     qi::blank, vectors);

後続の行の要素数qi::repeatを期待するために使用します。num_elementsそれを1次元配列に格納するだけです:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/spirit/include/karma.hpp>

namespace qi     = boost::spirit::qi;
namespace phx    = boost::phoenix;
namespace karma  = boost::spirit::karma;

int main()
{
    std::cin.unsetf(std::ios::skipws);
    boost::spirit::istream_iterator b(std::cin), e;

    //std::vector<std::vector<int> > vectors;
    std::vector<int> vectors;

    int num_elements = 0;
    bool ok = qi::phrase_parse(b, e, 
            (+qi::int_) [ phx::ref(num_elements) = phx::size(qi::_1) ]
         >> *(qi::eol >> qi::repeat(phx::ref(num_elements)) [ qi::int_ ])
         >> *qi::eol, 
         qi::blank, vectors);

    std::cout << "Detected num_elements: " << num_elements << "\n";

    if (!ok)
    {
        std::cerr << "Parse failed at '" << std::string(b,e) << "'\n";
        return 255;
    }

    if (b!=e)
        std::cout << "Trailing unparsed: '" << std::string(b,e) << "'\n";

    // print the data for verification
    std::cout 
        << karma::format_delimited(karma::columns(num_elements)[+karma::int_], ' ', vectors)
        << std::endl;

    return 0;
}

karma::columns(num_elements)を使用して、出力を行ごとに正しい列数に分割することに注意してください。

于 2013-04-21T15:30:21.697 に答える