I have a parser that parses into a boost::variant<int, double, std::string>
我有一个解析器,解析为boost :: variant
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
using namespace std;
typedef map<string, boost::variant<int, double, string> > namevalue;
typedef pair<string, boost::variant<int, double, string> > namevaluepair;
template <typename Iterator>
struct keys_and_values2
: grammar<Iterator, namevalue(), ascii::blank_type>
{
keys_and_values2()
: keys_and_values2::base_type(start)
{
start %= query >> qi::eoi;
query = +pair;
value = qi::int_ | qi::double_ | qi::lexeme[+(qi::char_ - qi::eol)] ;
pair = key >> qi::lit(':') >> value >> qi::eol;
key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
}
qi::rule<Iterator, namevalue(), ascii::blank_type> start;
qi::rule<Iterator, namevalue(), ascii::blank_type> query;
qi::rule<Iterator, namevaluepair(), ascii::blank_type> pair;
qi::rule<Iterator, std::string(), ascii::blank_type> key;
qi::rule<Iterator, boost::variant<int, double, string>(), ascii::blank_type> value;
};
the input to parse is here:
解析的输入在这里:
Sarai : 52.731199473801
Jamiya : Jelly Drop
Clara : -92.408605869885
Janelle : 132349223
Briley : -40.905352495602
This fails on the first line "Sarai". If I reverse the parsing of double and int like this:
这在第一行“Sarai”失败了。如果我像这样反转解析double和int:
value = qi::double_ | qi::int_ | qi::lexeme[+(qi::char_ - qi::eol)] ;
It works fine, but the integer value of "Janelle" is parsed as double. Following the BOOST FAQ and the BOOST documentation, I would like to use qi::hold[] like this:
它工作正常,但“Janelle”的整数值被解析为double。按照BOOST FAQ和BOOST文档,我想像这样使用qi :: hold []:
value = qi::hold[qi::int_] | qi::hold[qi::double_] | qi::lexeme[+(qi::char_ - qi::eol)] ;
But with this, I get a message about missing function: swap()
. This is actually documented in the boost docs (note). But the explanation is very terse. I am unable to find the correct attribute type for this swap function. Can anybody help here?
但有了这个,我收到一条关于缺少函数的消息:swap()。这实际上记录在boost docs(注释)中。但解释非常简洁。我无法找到此交换函数的正确属性类型。有人可以帮忙吗?
Compiler message here:
这里的编译器消息:
E:\Boost\boost_1_58_0\boost/spirit/home/support/attributes.hpp(1036) : error C2784: 'void boost::spirit::swap(boost::spirit::multi_pass<T,Policies> &,boost::spirit::multi_pass<T,Policies> &)' : could not deduce template argument for 'boost::spirit::multi_pass<T,Policies> &' from 'int'
Update
The answer of sehe works with the data above. However If I change the input to the following:
Sarai : 52.731199473801
Jamiya : Jelly Drop
Clara : -92.408605869885
Rebekah : 240ad9beb53bbfafcd5
Janelle : 132349223
Cloe : 456ABCabvc
Briley : -40.905352495602
I'll have a problem with the "Rebekah" value. I also see that the order in which the values are evaluated is important. This time, the issue is not with the double
value anymore, it is between the int
and the string
. I would like to implement something like this: (policy?)
我对“Rebekah”值有疑问。我还看到评估值的顺序很重要。这一次,问题不再是double值,而是在int和string之间。我想实现这样的事情:(政策?)
- everything that has only digits, an optional minus sign and contains a dot is a
double
- everything that has only digits and an optional minus sign is
int
- everything else is
std::string
只有数字,可选减号和包含点的所有内容都是双精度数
只有数字和可选减号的所有东西都是int
其他一切都是std :: string
Solution
Sometimes, it is more important to understand the question than the problem.
The issue was not the parser policy, it was my definition of the parsing rules (see above). Rule 3 "everything else" actually includes: "everything up to EOL". Therefore all three alternatives in the rule for value
have to match this:
问题不是解析器策略,而是我对解析规则的定义(见上文)。规则3“其他一切”实际上包括:“一切都符合EOL”。因此,价值规则中的所有三个备选方案必须与此匹配:
value = strict_double >> qi::eol
| qi::int_ >> qi::eol
| qi::lexeme[+(qi::char_ - qi::eol)] >> qi::eol;
With this change, sehe's answer just works like a charm!
随着这种变化,sehe的答案就像一个魅力!
1 个解决方案
#1
Hold is not used for this.
Hold不用于此。
Think about it: how would it help? It won't make the integer branch not match, so it will still fail to parse, and hold
doesn't revert anything.
想一想:它会有什么帮助?它不会使整数分支不匹配,因此它仍然无法解析,并且hold不会还原任何东西。
hold[]
is mainly useful for container attributes¹, where partial parses could have modified the attribute. Containers usually already have swap implemented. You were barking up the wrong tree here
hold []主要用于容器属性¹,其中部分解析可以修改属性。容器通常已经实现了交换。你在这里咆哮着错误的树
¹ including strings, see e.g.
• Understanding Boost.spirit's string parser
• boost::spirit::qi duplicate parsing on the output
• Boost spirit revert parsing
• Boost Spirit optional parser and backtracking¹包括字符串,参见例如•了解Boost.spirit的字符串解析器•boost :: spirit :: qi在输出上重复解析•Boost精神还原解析•Boost Spirit可选解析器和回溯
Solving the problem:
You can use the strict real policy to parse only real values as double.
您可以使用严格实际策略仅将实际值解析为double。
value = strict_double | qi::int_ | qi::lexeme[+(qi::char_ - qi::eol)] ;
// with
qi::real_parser<double, qi::strict_real_policies<double> > strict_double;
See also Parse int or double using boost spirit (longest_d) for some unit tests
另请参阅Parse int或使用boost spirit(longest_d)进行一些单元测试
住在Coliru
#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <map>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
typedef boost::variant<int, double, std::string> value_t;
typedef std::map<std::string, value_t> namevalue;
typedef std::pair<std::string, value_t> namevaluepair;
template <typename Iterator>
struct keys_and_values2
: qi::grammar<Iterator, namevalue(), ascii::blank_type>
{
keys_and_values2() : keys_and_values2::base_type(start)
{
start %= query >> qi::eoi;
query = +pair;
value = strict_double | qi::int_ | qi::lexeme[+(qi::char_ - qi::eol)] ;
pair = key >> qi::lit(':') >> value >> qi::eol;
key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
BOOST_SPIRIT_DEBUG_NODES((start)(query)(value)(pair)(key))
}
private:
qi::real_parser<double, qi::strict_real_policies<double> > strict_double;
qi::rule<Iterator, namevalue(), ascii::blank_type> start;
qi::rule<Iterator, namevalue(), ascii::blank_type> query;
qi::rule<Iterator, namevaluepair(), ascii::blank_type> pair;
qi::rule<Iterator, std::string(), ascii::blank_type> key;
qi::rule<Iterator, value_t(), ascii::blank_type> value;
};
int main() {
typedef boost::spirit::istream_iterator It;
It f(std::cin >> std::noskipws), l;
keys_and_values2<It> g;
namevalue data;
bool ok = qi::phrase_parse(f,l,g,ascii::blank,data);
if (ok) {
std::cout << "Parse succeeded:\n";
for(auto& p : data)
std::cout << "\t'" << p.first << "'\t-> " << p.second << "\n";
} else
std::cout << "Parse failed\n";
if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
Prints
Parse succeeded:
'Briley' -> -40.9054
'Clara' -> -92.4086
'Jamiya' -> Jelly Drop
'Janelle' -> 132349223
'Sarai' -> 52.7312
And the debug info (if enabled)
调试信息(如果启用)
<start>
<try>Sarai : 52.731</try>
<query>
<try>Sarai : 52.731</try>
<pair>
<try>Sarai : 52.731</try>
<key>
<try>Sarai : 52.731</try>
<success>: 52.731199473801</success>
<attributes>[[S, a, r, a, i]]</attributes>
</key>
<value>
<try> 52.731199473801\n</try>
<success>\nJamiya : Jelly</success>
<attributes>[52.7312]</attributes>
</value>
<success>Jamiya : Jelly </success>
<attributes>[[[S, a, r, a, i], 52.7312]]</attributes>
</pair>
<pair>
<try>Jamiya : Jelly </try>
<key>
<try>Jamiya : Jelly </try>
<success>: Jelly Drop\nClar</success>
<attributes>[[J, a, m, i, y, a]]</attributes>
</key>
<value>
<try> Jelly Drop\nClara</try>
<success>\nClara : -92.4</success>
<attributes>[[J, e, l, l, y, , D, r, o, p]]</attributes>
</value>
<success>Clara : -92.40</success>
<attributes>[[[J, a, m, i, y, a], [J, e, l, l, y, , D, r, o, p]]]</attributes>
</pair>
<pair>
<try>Clara : -92.40</try>
<key>
<try>Clara : -92.40</try>
<success>: -92.40860586988</success>
<attributes>[[C, l, a, r, a]]</attributes>
</key>
<value>
<try> -92.408605869885</try>
<success>\nJanelle : 13234</success>
<attributes>[-92.4086]</attributes>
</value>
<success>Janelle : 132349</success>
<attributes>[[[C, l, a, r, a], -92.4086]]</attributes>
</pair>
<pair>
<try>Janelle : 132349</try>
<key>
<try>Janelle : 132349</try>
<success>: 132349223\nBrile</success>
<attributes>[[J, a, n, e, l, l, e]]</attributes>
</key>
<value>
<try> 132349223\nBriley</try>
<success>\nBriley : -40.9</success>
<attributes>[132349223]</attributes>
</value>
<success>Briley : -40.90</success>
<attributes>[[[J, a, n, e, l, l, e], 132349223]]</attributes>
</pair>
<pair>
<try>Briley : -40.90</try>
<key>
<try>Briley : -40.90</try>
<success>: -40.90535249560</success>
<attributes>[[B, r, i, l, e, y]]</attributes>
</key>
<value>
<try> -40.905352495602</try>
<success>\n</success>
<attributes>[-40.9054]</attributes>
</value>
<success></success>
<attributes>[[[B, r, i, l, e, y], -40.9054]]</attributes>
</pair>
<pair>
<try></try>
<key>
<try></try>
<fail/>
</key>
<fail/>
</pair>
<success></success>
<attributes>[[[[B, r, i, l, e, y], -40.9054], [[C, l, a, r, a], -92.4086], [[J, a, m, i, y, a], [J, e, l, l, y, , D, r, o, p]], [[J, a, n, e, l, l, e], 132349223], [[S, a, r, a, i], 52.7312]]]</attributes>
</query>
<success></success>
<attributes>[[[[B, r, i, l, e, y], -40.9054], [[C, l, a, r, a], -92.4086], [[J, a, m, i, y, a], [J, e, l, l, y, , D, r, o, p]], [[J, a, n, e, l, l, e], 132349223], [[S, a, r, a, i], 52.7312]]]</attributes>
</start>
#1
Hold is not used for this.
Hold不用于此。
Think about it: how would it help? It won't make the integer branch not match, so it will still fail to parse, and hold
doesn't revert anything.
想一想:它会有什么帮助?它不会使整数分支不匹配,因此它仍然无法解析,并且hold不会还原任何东西。
hold[]
is mainly useful for container attributes¹, where partial parses could have modified the attribute. Containers usually already have swap implemented. You were barking up the wrong tree here
hold []主要用于容器属性¹,其中部分解析可以修改属性。容器通常已经实现了交换。你在这里咆哮着错误的树
¹ including strings, see e.g.
• Understanding Boost.spirit's string parser
• boost::spirit::qi duplicate parsing on the output
• Boost spirit revert parsing
• Boost Spirit optional parser and backtracking¹包括字符串,参见例如•了解Boost.spirit的字符串解析器•boost :: spirit :: qi在输出上重复解析•Boost精神还原解析•Boost Spirit可选解析器和回溯
Solving the problem:
You can use the strict real policy to parse only real values as double.
您可以使用严格实际策略仅将实际值解析为double。
value = strict_double | qi::int_ | qi::lexeme[+(qi::char_ - qi::eol)] ;
// with
qi::real_parser<double, qi::strict_real_policies<double> > strict_double;
See also Parse int or double using boost spirit (longest_d) for some unit tests
另请参阅Parse int或使用boost spirit(longest_d)进行一些单元测试
住在Coliru
#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <map>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
typedef boost::variant<int, double, std::string> value_t;
typedef std::map<std::string, value_t> namevalue;
typedef std::pair<std::string, value_t> namevaluepair;
template <typename Iterator>
struct keys_and_values2
: qi::grammar<Iterator, namevalue(), ascii::blank_type>
{
keys_and_values2() : keys_and_values2::base_type(start)
{
start %= query >> qi::eoi;
query = +pair;
value = strict_double | qi::int_ | qi::lexeme[+(qi::char_ - qi::eol)] ;
pair = key >> qi::lit(':') >> value >> qi::eol;
key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
BOOST_SPIRIT_DEBUG_NODES((start)(query)(value)(pair)(key))
}
private:
qi::real_parser<double, qi::strict_real_policies<double> > strict_double;
qi::rule<Iterator, namevalue(), ascii::blank_type> start;
qi::rule<Iterator, namevalue(), ascii::blank_type> query;
qi::rule<Iterator, namevaluepair(), ascii::blank_type> pair;
qi::rule<Iterator, std::string(), ascii::blank_type> key;
qi::rule<Iterator, value_t(), ascii::blank_type> value;
};
int main() {
typedef boost::spirit::istream_iterator It;
It f(std::cin >> std::noskipws), l;
keys_and_values2<It> g;
namevalue data;
bool ok = qi::phrase_parse(f,l,g,ascii::blank,data);
if (ok) {
std::cout << "Parse succeeded:\n";
for(auto& p : data)
std::cout << "\t'" << p.first << "'\t-> " << p.second << "\n";
} else
std::cout << "Parse failed\n";
if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
Prints
Parse succeeded:
'Briley' -> -40.9054
'Clara' -> -92.4086
'Jamiya' -> Jelly Drop
'Janelle' -> 132349223
'Sarai' -> 52.7312
And the debug info (if enabled)
调试信息(如果启用)
<start>
<try>Sarai : 52.731</try>
<query>
<try>Sarai : 52.731</try>
<pair>
<try>Sarai : 52.731</try>
<key>
<try>Sarai : 52.731</try>
<success>: 52.731199473801</success>
<attributes>[[S, a, r, a, i]]</attributes>
</key>
<value>
<try> 52.731199473801\n</try>
<success>\nJamiya : Jelly</success>
<attributes>[52.7312]</attributes>
</value>
<success>Jamiya : Jelly </success>
<attributes>[[[S, a, r, a, i], 52.7312]]</attributes>
</pair>
<pair>
<try>Jamiya : Jelly </try>
<key>
<try>Jamiya : Jelly </try>
<success>: Jelly Drop\nClar</success>
<attributes>[[J, a, m, i, y, a]]</attributes>
</key>
<value>
<try> Jelly Drop\nClara</try>
<success>\nClara : -92.4</success>
<attributes>[[J, e, l, l, y, , D, r, o, p]]</attributes>
</value>
<success>Clara : -92.40</success>
<attributes>[[[J, a, m, i, y, a], [J, e, l, l, y, , D, r, o, p]]]</attributes>
</pair>
<pair>
<try>Clara : -92.40</try>
<key>
<try>Clara : -92.40</try>
<success>: -92.40860586988</success>
<attributes>[[C, l, a, r, a]]</attributes>
</key>
<value>
<try> -92.408605869885</try>
<success>\nJanelle : 13234</success>
<attributes>[-92.4086]</attributes>
</value>
<success>Janelle : 132349</success>
<attributes>[[[C, l, a, r, a], -92.4086]]</attributes>
</pair>
<pair>
<try>Janelle : 132349</try>
<key>
<try>Janelle : 132349</try>
<success>: 132349223\nBrile</success>
<attributes>[[J, a, n, e, l, l, e]]</attributes>
</key>
<value>
<try> 132349223\nBriley</try>
<success>\nBriley : -40.9</success>
<attributes>[132349223]</attributes>
</value>
<success>Briley : -40.90</success>
<attributes>[[[J, a, n, e, l, l, e], 132349223]]</attributes>
</pair>
<pair>
<try>Briley : -40.90</try>
<key>
<try>Briley : -40.90</try>
<success>: -40.90535249560</success>
<attributes>[[B, r, i, l, e, y]]</attributes>
</key>
<value>
<try> -40.905352495602</try>
<success>\n</success>
<attributes>[-40.9054]</attributes>
</value>
<success></success>
<attributes>[[[B, r, i, l, e, y], -40.9054]]</attributes>
</pair>
<pair>
<try></try>
<key>
<try></try>
<fail/>
</key>
<fail/>
</pair>
<success></success>
<attributes>[[[[B, r, i, l, e, y], -40.9054], [[C, l, a, r, a], -92.4086], [[J, a, m, i, y, a], [J, e, l, l, y, , D, r, o, p]], [[J, a, n, e, l, l, e], 132349223], [[S, a, r, a, i], 52.7312]]]</attributes>
</query>
<success></success>
<attributes>[[[[B, r, i, l, e, y], -40.9054], [[C, l, a, r, a], -92.4086], [[J, a, m, i, y, a], [J, e, l, l, y, , D, r, o, p]], [[J, a, n, e, l, l, e], 132349223], [[S, a, r, a, i], 52.7312]]]</attributes>
</start>