3

を使用して、他のパラメーターからパーサーを動的に構築しようとしていますboost::spirit:qi。目標は、文字列を解析し、std::map<std::string, std::string>キーと値を入力することです。ただし、マップのキー フィールドは解析されません (つまり、パーサーが生成される前に認識されます)。

マップのキーを適切な解析値に設定するセマンティック アクションを記述する必要があると思います。がパーサーのコンテンツを提供していることはわかりqi::_1ますが、戻り構造 (この場合は a ) を参照するにはどうすればよいstd::mapでしょうか?

範囲内にある場合は、次のstd::mapように直接割り当てることができます。

parser = lit(prefix) >> value_parser[map_[key] = _1];

しかし、私の場合、解析を行うのではなく、実際にパーサーを生成したいと考えています。交換するものが必要だと思いますmap_[key]


もう少しコンテキストを提供するには (要求に応じて):

最初に、次のような「テンプレート」文字列を解析します。

/path/to/:somewhere:/nifty.json

:somewhere:、後で name によって参照できる任意の文字列を表すことを意図していますsomewhere。私はそのパーサーをうまく機能させています。

次に、そのテンプレートから、次のような文字列を解析する別のパーサーを生成します。

/path/to/anywhere/nifty.json

そして、私にstd::map<std::string, std::string> mwhereを提供してくださいm["somewhere"] == "anywhere"

4

2 に答える 2

3

これがあなたが考えていたものであるかどうかはわかりませんが、継承された属性があなたの答えかもしれません。パーサーを動的に作成する代わりに、呼び出しごとに提供する継承された属性として、キーとマップへの参照を取得する単一のパーサーを作成します。

// an attempt to demonstrate a parser that takes a std::map by reference and a key by value,
// then stores a parsed value into the map as the value associated with the given key

#include <string>
#include <map>

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

typedef std::string::const_iterator fwd_iter_t;

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

typedef int value_t;  // or whatever
typedef std::map<std::string, value_t> result_map_t;
// key insight - rules can take "inherited" attributes (parameters in 2nd argument):
typedef qi::rule<fwd_iter_t,
                 void(result_map_t&, std::string),       // inherit map ref and key to use
                 boost::spirit::ascii::space_type> map_insert_rule_t;

int main() {

   result_map_t result_map;
   std::vector<std::string> keys = { "A", "B", "C" };
   std::string test_data = "PREFIX 1\nPREFIX 2\nPREFIX 3";

   using boost::phoenix::construct;   // to create pairs
   using boost::phoenix::insert;      // to add pairs to the map
   typedef result_map_t::value_type result_map_pair_t;
   // use Phoenix actions to construct the key/value pair and insert it
   map_insert_rule_t maprule = qi::lit("PREFIX")
                            >> qi::int_[insert(qi::_r1,   // inherited map ref
                                               construct<result_map_pair_t>(qi::_r2, qi::_1))];

   fwd_iter_t beg = test_data.begin();
   fwd_iter_t end = test_data.end();
   for (auto k_it = keys.begin(); k_it != keys.end(); ++k_it) {
      using boost::spirit::ascii::space;
      if (!qi::phrase_parse(beg, end,
                            maprule(phoenix::ref(result_map), *k_it),
                            space)) {
         std::cerr << "parse failed!" << std::endl;
         return 1;
      }
   }

   std::cout << "parse results:" << std::endl;
   for (auto r_it = result_map.begin(); r_it != result_map.end(); ++r_it) {
      std::cout << r_it->first << " " << r_it->second << std::endl;
   }

   return 0;
}

qi :: ruleから継承し、それをプライベートデータメンバーにすることで、呼び出しからstd::map参照を削除できる可能性があります。

于 2013-02-13T00:33:43.703 に答える
1

あなたが求めていることを行うためにphoenix bindを使用できるはずですが、もう少しコンテキストがあれば、よりクリーンなソリューションが利用できるようです.

parser = lit(prefix) >> value_parser[phx::ref(map)[key] = qi::_1]

キーの取得元によっては、phx::ref も使用する必要がある場合があります。

于 2013-02-12T23:57:56.873 に答える