如何使用 qi::hold[] 解析器指令。 (boost::swap 的属性类型问题)
How to use the qi::hold[] Parser directive. (Issue with attribute type for boost::swap)
我有一个解析器可以解析成 boost::variant<int, double, std::string>
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;
};
要解析的输入在这里:
Sarai : 52.731199473801
Jamiya : Jelly Drop
Clara : -92.408605869885
Janelle : 132349223
Briley : -40.905352495602
第一行失败 "Sarai"。如果我像这样反转 double 和 int 的解析:
value = qi::double_ | qi::int_ | qi::lexeme[+(qi::char_ - qi::eol)] ;
它工作正常,但 "Janelle" 的整数值被解析为 double。在 BOOST FAQ and the BOOST documentation 之后,我想像这样使用 qi::hold[]:
value = qi::hold[qi::int_] | qi::hold[qi::double_] | qi::lexeme[+(qi::char_ - qi::eol)] ;
但是有了这个,我收到了一条关于缺少功能的消息:swap()
。这实际上记录在 boost 文档中(注)。但解释非常简洁。我无法找到此交换功能的正确属性类型。有人可以帮忙吗?
这里的编译器消息:
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'
更新
适用于上述数据。但是,如果我将输入更改为以下内容:
Sarai : 52.731199473801
Jamiya : Jelly Drop
Clara : -92.408605869885
Rebekah : 240ad9beb53bbfafcd5
Janelle : 132349223
Cloe : 456ABCabvc
Briley : -40.905352495602
"Rebekah" 值有问题。我还看到评估值的顺序很重要。这一次,问题不再与 double
值有关,而是在 int
和 string
之间。我想实施这样的事情:(政策?)
- 所有只有数字、一个可选的减号并包含一个点的东西都是
double
- 只有数字和可选减号的所有内容都是
int
- 其他都是
std::string
解决方案
有时候,理解问题比问题更重要
问题不是解析器策略,而是我对解析规则的定义(见上文)。规则 3 "everything else" 实际上包括:"everything up to EOL"。因此 value
规则中的所有三个备选方案都必须匹配:
value = strict_double >> qi::eol
| qi::int_ >> qi::eol
| qi::lexeme[+(qi::char_ - qi::eol)] >> qi::eol;
有了这个改变, 就像一个魅力!
保留不用于此目的。
想一想:这会有什么帮助?它不会使整数分支不匹配,因此它仍然无法解析,并且 hold
不会还原任何内容。
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
解决问题:
您可以使用严格的实数策略仅将实数值解析为双精度值。
value = strict_double | qi::int_ | qi::lexeme[+(qi::char_ - qi::eol)] ;
// with
qi::real_parser<double, qi::strict_real_policies<double> > strict_double;
另请参阅 Parse int or double using boost spirit (longest_d) 了解一些单元测试
#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";
}
版画
Parse succeeded:
'Briley' -> -40.9054
'Clara' -> -92.4086
'Jamiya' -> Jelly Drop
'Janelle' -> 132349223
'Sarai' -> 52.7312
和调试信息(如果启用)
<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>
我有一个解析器可以解析成 boost::variant<int, double, std::string>
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;
};
要解析的输入在这里:
Sarai : 52.731199473801
Jamiya : Jelly Drop
Clara : -92.408605869885
Janelle : 132349223
Briley : -40.905352495602
第一行失败 "Sarai"。如果我像这样反转 double 和 int 的解析:
value = qi::double_ | qi::int_ | qi::lexeme[+(qi::char_ - qi::eol)] ;
它工作正常,但 "Janelle" 的整数值被解析为 double。在 BOOST FAQ and the BOOST documentation 之后,我想像这样使用 qi::hold[]:
value = qi::hold[qi::int_] | qi::hold[qi::double_] | qi::lexeme[+(qi::char_ - qi::eol)] ;
但是有了这个,我收到了一条关于缺少功能的消息:swap()
。这实际上记录在 boost 文档中(注)。但解释非常简洁。我无法找到此交换功能的正确属性类型。有人可以帮忙吗?
这里的编译器消息:
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'
更新
Sarai : 52.731199473801
Jamiya : Jelly Drop
Clara : -92.408605869885
Rebekah : 240ad9beb53bbfafcd5
Janelle : 132349223
Cloe : 456ABCabvc
Briley : -40.905352495602
"Rebekah" 值有问题。我还看到评估值的顺序很重要。这一次,问题不再与 double
值有关,而是在 int
和 string
之间。我想实施这样的事情:(政策?)
- 所有只有数字、一个可选的减号并包含一个点的东西都是
double
- 只有数字和可选减号的所有内容都是
int
- 其他都是
std::string
解决方案
有时候,理解问题比问题更重要
问题不是解析器策略,而是我对解析规则的定义(见上文)。规则 3 "everything else" 实际上包括:"everything up to EOL"。因此 value
规则中的所有三个备选方案都必须匹配:
value = strict_double >> qi::eol
| qi::int_ >> qi::eol
| qi::lexeme[+(qi::char_ - qi::eol)] >> qi::eol;
有了这个改变,
保留不用于此目的。
想一想:这会有什么帮助?它不会使整数分支不匹配,因此它仍然无法解析,并且 hold
不会还原任何内容。
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
解决问题:
您可以使用严格的实数策略仅将实数值解析为双精度值。
value = strict_double | qi::int_ | qi::lexeme[+(qi::char_ - qi::eol)] ;
// with
qi::real_parser<double, qi::strict_real_policies<double> > strict_double;
另请参阅 Parse int or double using boost spirit (longest_d) 了解一些单元测试
#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";
}
版画
Parse succeeded:
'Briley' -> -40.9054
'Clara' -> -92.4086
'Jamiya' -> Jelly Drop
'Janelle' -> 132349223
'Sarai' -> 52.7312
和调试信息(如果启用)
<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>