簡體   English   中英

如何使用boost :: spirit將文本解析為結構?

[英]How to parse text into a struct using boost::spirit?

我正在學習boost::spirit ,我正在嘗試閱讀並解析一些文本到結構中。

例如,在我的TestStruct中, "2: 4.6"被解析為int 2和double 4.6

#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/fusion/include/std_pair.hpp>
namespace qi = boost::spirit::qi;

struct TestStruct {
  int myint;
  double mydouble;
  TestStruct() {}
  TestStruct(std::pair<int,double> p) : myint(p.first), mydouble(p.second) {}
};

template <typename Iterator, typename Skipper>
struct MyGrammar : qi::grammar<Iterator, TestStruct(), Skipper> {
  MyGrammar() : MyGrammar::base_type(mystruct) {
    mystruct0 = qi::int_ >> ":" >> qi::double_;
    mystruct = mystruct0;
  }
  qi::rule<Iterator, std::pair<int,double>(), Skipper> mystruct0;
  qi::rule<Iterator, TestStruct(), Skipper> mystruct;
};

int main() {
  typedef boost::spirit::istream_iterator It;
  std::cin.unsetf(std::ios::skipws);
  It it(std::cin), end; // input example: "2: 3.4"                                                                              

  MyGrammar<It, qi::space_type> gr;
  TestStruct ts;
  if (qi::phrase_parse(it, end, gr, qi::space, ts) && it == end)
    std::cout << ts.myint << ", " << ts.mydouble << std::endl;
  return 0;
}

它很好用,但我想知道如何簡化這段代碼?

例如,我想擺脫mystruct0語法規則,它只用於標記類型std::pair<int,double> ,然后用於從mystruct規則自動構造TestStruct對象。

我還希望能夠從std::pair刪除TestStruct構造函數,如果可能的話。

那么,以下代碼可以以某種方式編譯嗎? 這將是一個更好的解決方案:

struct TestStruct {
  int myint;
  double mydouble;
  TestStruct() {}
  TestStruct(int i, double d) : myint(i), mydouble(d) {}
};

template <typename Iterator, typename Skipper>
struct MyGrammar : qi::grammar<Iterator, TestStruct(), Skipper> {
  MyGrammar() : MyGrammar::base_type(mystruct) {
    mystruct = qi::int_ >> ":" >> qi::double_;
  }
  qi::rule<Iterator, TestStruct(), Skipper> mystruct;
};

int main() {
  typedef boost::spirit::istream_iterator It;
  std::cin.unsetf(std::ios::skipws);
  It it(std::cin), end; // input example: "2: 3.4"                                                                              

  MyGrammar<It, qi::space_type> gr;
  TestStruct ts;
  if (qi::phrase_parse(it, end, gr, qi::space, ts) && it == end)
    std::cout << ts.myint << ", " << ts.mydouble << std::endl;
  return 0;
}

不幸的是,編譯器說:

boost_1_49_0/include/boost/spirit/home/qi/detail/assign_to.hpp:123: 
error: no matching function for call to ‘TestStruct::TestStruct(const int&)’

為了能值“順序”解析成一個結構,你需要把它改造成一個fusion所描述的元組, 在這里

在你的情況下,這意味着你需要

  1. 包括必要的標題

     #include <boost/fusion/adapted/struct/adapt_struct.hpp> 
  2. 使用fusion-adapt struct宏。 TestStruct聲明后的最佳位置:

     BOOST_FUSION_ADAPT_STRUCT( TestStruct, (int,myint) (double,mydouble) ) 

通過這兩個更改,您的簡化版本將編譯並生成所需的結果。 不確定它現在是否真的更簡單 - 但是如果你打算在你的結構中添加更多成員,這是一個很好的起點,因為它可能有助於簡化未來的事情。

我沒有看到任何其他重大更改可以使程序更簡單。

是的,可以編譯代碼。 實際上,您可以不使用構造函數:默認(編譯器生成的)構造函數很好。

您需要做的就是將結構調整為融合序列。 (作為獎勵,這也適用於業力。)
這正是讓std::pair首先發揮作用的神奇之處。

#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted/struct.hpp>
namespace qi = boost::spirit::qi;

struct TestStruct {
    int myint;
    double mydouble;
};

BOOST_FUSION_ADAPT_STRUCT(TestStruct, (int, myint)(double, mydouble));

template <typename Iterator, typename Skipper>
struct MyGrammar : qi::grammar<Iterator, TestStruct(), Skipper> {
    MyGrammar() : MyGrammar::base_type(mystruct) {
        mystruct = qi::int_ >> ":" >> qi::double_;
    }
    qi::rule<Iterator, TestStruct(), Skipper> mystruct;
};

int main() {
    typedef std::string::const_iterator It;
    const std::string input("2: 3.4");
    It it(input.begin()), end(input.end());

    MyGrammar<It, qi::space_type> gr;
    TestStruct ts;

    if (qi::phrase_parse(it, end, gr, qi::space, ts) && it == end)
        std::cout << ts.myint << ", " << ts.mydouble << std::endl;

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM