我正在嘗試將由“,”分隔的字符序列決議為 std::map<char,int> 對,其中鍵是字符,值只是已決議字符的計數。例如,如果輸入是
a,b,c
地圖應包含以下對:
(a,1) , (b,2) , (c,3)
這是我正在使用的代碼:
namespace myparser
{
std::map<int, std::string> mapping;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
int i = 0;
template <typename Iterator>
bool parse_numbers(Iterator first, Iterator last, std::map<char,int>& v)
{
using qi::double_;
using qi::char_;
using qi::phrase_parse;
using qi::_1;
using ascii::space;
using phoenix::push_back;
bool r = phrase_parse(first, last,
// Begin grammar
(
char_[v.insert(std::make_pair(_1,0)]
>> *(',' >> char_[v.insert(std::make_pair(_1,0)])
)
,
// End grammar
space);
if (first != last) // fail if we did not get a full match
return false;
return r;
}
//]
}
然后我嘗試像這樣在 main 中列印這對:
int main() {
std::string str;
while (getline(std::cin, str))
{
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
break;
std::map<char,int> v;
std::map<std::string, int>::iterator it = v.begin();
if (myparser::parse_numbers(str.begin(), str.end(), v))
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << str << " Parses OK: " << std::endl;
while (it != v.end())
{
// Accessing KEY from element pointed by it.
std::string word = it->first;
// Accessing VALUE from element pointed by it.
int count = it->second;
std::cout << word << " :: " << count << std::endl;
// Increment the Iterator to point to next entry
it ;
}
std::cout << "\n-------------------------\n";
}
else
{
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "-------------------------\n";
}
}
return 0;
}
我是初學者,我不知道如何修復此代碼。我還想使用字串而不是字符,所以我輸入了一個由“,”分隔的字串序列,并將它們存盤在類似于上面提到的映射中。我將不勝感激任何幫助 !
uj5u.com熱心網友回復:
您不能在 Phoenix 延遲演員之外使用 Phoenix 占位符。例如 的型別std::make_pair(qi::_1, 0)是std::pair<boost::phoenix::actor<boost::phoenix::argument<0>>, int>。
沒有任何東西可以與這樣的東西互操作。當然不是std::map<>::insert。
您需要做的是將所有操作包裝為 Phoenix 演員的語意動作。
#include <boost/phoenix.hpp>
namespace px = boost::phoenix;
那么你也能:
#include <boost/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
namespace myparser {
using Map = std::map<char, int>;
template <typename Iterator>
bool parse_numbers(Iterator first, Iterator last, Map& m) {
auto action = px::insert(px::ref(m), px::end(px::ref(m)),
px::construct<std::pair<char, int>>(qi::_1, 0));
bool r = qi::phrase_parse( //
first, last,
// Begin grammar
qi::char_[action] >> *(',' >> qi::char_[action]),
// End grammar
qi::space);
return r && first == last;
}
} // namespace myparser
現場觀看
十分簡單。正確的。
我花了半個小時在那東西上除錯它為什么不起作用。為什么這么難?
這是因為有人發明了一個完整的元 DSL 來撰寫“普通 C ”,但執行延遲。在那發生的時候,它非常整潔,但它是所有泄漏抽象的母親,具有鋒利的邊緣。
那么,有什么新東西呢?使用 C 11,您可以:
居住
template <typename Iterator>
bool parse_numbers(Iterator first, Iterator last, Map& m) {
struct action_f {
Map& m_;
void operator()(char ch) const { m_.emplace(ch, 0); }
};
px::function<action_f> action{{m}};
bool r = qi::phrase_parse( //
first, last,
// Begin grammar
qi::char_[action(qi::_1)] >> *(',' >> qi::char_[action(qi::_1)]),
// End grammar
qi::space);
return r && first == last;
}
或使用 c 17:
居住
template <typename Iterator>
bool parse_numbers(Iterator first, Iterator last, Map& m) {
px::function action{[&m](char ch) { m.emplace(ch, 0); }};
bool r = qi::phrase_parse( //
first, last,
// Begin grammar
qi::char_[action(qi::_1)] >> *(',' >> qi::char_[action(qi::_1)]),
// End grammar
qi::space);
return r && first == last;
}
在切線上,您可能想計算事物,所以,也許使用
居住
px::function action{[&m](char ch) { m[ch] = 1; }};
此時,您可以切換到 Spirit X3(需要 C 14):
居住
#include <boost/spirit/home/x3.hpp>
#include <map>
namespace x3 = boost::spirit::x3;
namespace myparser {
using Map = std::map<char, int>;
template <typename Iterator>
bool parse_numbers(Iterator first, Iterator last, Map& m) {
auto action = [&m](auto& ctx) { m[_attr(ctx)] = 1; };
return x3::phrase_parse( //
first, last,
// Begin grammar
x3::char_[action] >> *(',' >> x3::char_[action]) >> x3::eoi,
// End grammar
x3::space);
}
} // namespace myparser
最后,讓我們簡化一下。p >> *(',' >> p)只是一種笨拙的說法p % ',':
居住
template <typename Iterator>
bool parse_numbers(Iterator first, Iterator last, Map& m) {
auto action = [&m](auto& ctx) { m[_attr(ctx)] = 1; };
return x3::phrase_parse( //
first, last, //
x3::char_[action] % ',', //
x3::space);
}
你想要的是文字,而不是字符:
居住
#include <boost/spirit/home/x3.hpp>
#include <map>
namespace x3 = boost::spirit::x3;
namespace myparser {
using Map = std::map<std::string, int>;
template <typename Iterator>
bool parse_numbers(Iterator first, Iterator last, Map& m) {
auto action = [&m](auto& ctx) { m[_attr(ctx)] = 1; };
auto word_ = (*~x3::char_(','))[action];
return phrase_parse(first, last, word_ % ',', x3::space);
}
} // namespace myparser
#include <iomanip>
#include <iostream>
int main() {
for (std::string const str : {"foo,c is strange,bar,qux,foo,c is strange ,cuz"}) {
std::map<std::string, int> m;
std::cout << "Parsing " << std::quoted(str) << std::endl;
if (myparser::parse_numbers(str.begin(), str.end(), m)) {
std::cout << m.size() << " words:\n";
for (auto& [word,count]: m)
std::cout << " - " << std::quoted(word) << " :: " << count << std::endl;
} else {
std::cerr << "Parsing failed\n";
}
}
}
印刷
Parsing "foo,c is strange,bar,qux,foo,c is strange ,cuz"
5 words:
- "bar" :: 1
- "c isstrange" :: 2
- "cuz" :: 1
- "foo" :: 2
- "qux" :: 1
注意x3::space(likeqi::space和qi::ascii::spaceabove)的行為。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/484539.html
