我必须处理文本格式的很长的整数-直到它们不适合32位int为止。 我需要将此类文本解析为
boost::variant<int, double>.
因此,如果一个整数有一个长整数到大整数,则需要加倍。请参见下面的示例。它不会解析名称值对
MUESR1 = 411100000000000.
如何解决?
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <iterator>
namespace qi = boost::spirit::qi;
namespace spirit = boost::spirit;
namespace ascii = boost::spirit::ascii;
typedef boost::variant<int, double> VALUE;
typedef std::pair<std::string, VALUE> PAIR;
typedef std::map<std::string, VALUE> PAIRS;
template<typename Iterator>
struct parameters:qi::grammar<Iterator, PAIRS(), ascii::space_type>
{
qi::rule<Iterator, std::string(), ascii::space_type> m_sName;
qi::rule<Iterator, VALUE(), ascii::space_type> m_sValue;
qi::rule<Iterator, PAIR(), ascii::space_type> m_sNameValue;
qi::rule<Iterator, PAIRS(), ascii::space_type> m_sRoot;
qi::real_parser<double, qi::strict_real_policies<double> > m_sReal;
parameters(void)
:parameters::base_type(m_sRoot)
{ m_sName %= qi::lexeme[qi::char_("a-zA-Z_") >> *qi::char_("a-zA-z_0-9")];
m_sValue %= m_sReal | spirit::int_;
m_sNameValue %= m_sName >> qi::lit('=') >> m_sValue >> -qi::lit('\n');
m_sRoot %= m_sNameValue >> *m_sNameValue;
}
};
int main(int, char**)
{
static const char s_ap[] = "\
MUEPH1 = 7.014158 MUEPHW= -0.3 MUEPWP = 0.23 MUEPHL= -0.72 MUEPLP = 3.4 MUEPHS = 2.976E-07 MUEPSP = 5 VTMP= -1.8463 WVTH0= -1.01558 MUESR0 = 0.01256478438899837 MUESR1 = 411100000000000\n\
MUEPHW2 = 0 MUEPWP2 = 1\n";
parameters<const char*> sGrammar;
const char *pIter = s_ap;
const char *const pEnd = s_ap + sizeof s_ap - 1;
PAIRS sValues;
if (phrase_parse(pIter, pEnd, sGrammar, boost::spirit::ascii::space, sValues) && pIter == pEnd)
{ std::cerr << "parsing successful!" << std::endl;
for (const auto &r : sValues)
std::cout << r.first << "=" << std::scientific << r.second << std::endl;
}
else
{ std::cerr << "parsing failed!" << std::endl;
std::cerr << pIter << std::endl;
}
}
答案 0 :(得分:1)
是的,语法只要求解析严格的实数。如果您不希望这样做,则需要接受其他实数。 @llonesmiz的评论是做到这一点的一种方法。
或者,您似乎可以解析双打。尽管二进制实数表示形式可能是“有损的”,但在超过有效位(https://en.wikipedia.org/wiki/Double-precision_floating-point_format)的52/53位之前,尾数的整数部分不会发生这种情况。相比之下,流行的编译器的
int
为32位。
//#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/include/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iterator>
#include <iomanip>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
typedef boost::variant<int, double> VALUE;
typedef std::pair<std::string, VALUE> PAIR;
typedef std::map<std::string, VALUE> PAIRS;
template <typename Iterator> struct parameters : qi::grammar<Iterator, PAIRS(), ascii::space_type> {
parameters(void) : parameters::base_type(m_sRoot) {
m_sName = qi::lexeme[qi::char_("a-zA-Z_") >> *qi::char_("a-zA-z_0-9")];
m_sValue = m_sReal | qi::int_ | qi::double_;
m_sNameValue = m_sName >> '=' >> m_sValue >> -qi::lit('\n');
m_sRoot = m_sNameValue >> *m_sNameValue;
BOOST_SPIRIT_DEBUG_NODES((m_sName)(m_sValue)(m_sNameValue)(m_sRoot))
}
private:
qi::rule<Iterator, std::string(), ascii::space_type> m_sName;
qi::rule<Iterator, VALUE(), ascii::space_type> m_sValue;
qi::rule<Iterator, PAIR(), ascii::space_type> m_sNameValue;
qi::rule<Iterator, PAIRS(), ascii::space_type> m_sRoot;
qi::real_parser<double, qi::strict_real_policies<double> > m_sReal;
};
int main(int, char **) {
static const char s_ap[] = R"(
MUEPH1 = 7.014158 MUEPHW= -0.3 MUEPWP = 0.23 MUEPHL= -0.72 MUEPLP = 3.4 MUEPHS = 2.976E-07 MUEPSP = 5 VTMP= -1.8463 WVTH0= -1.01558 MUESR0 = 0.01256478438899837 MUESR1 = 411100000000000
MUEPHW2 = 0 MUEPWP2 = 1
)";
parameters<const char*> sGrammar;
const char *pIter = std::begin(s_ap);
const char *const pEnd = std::end(s_ap) - 1;
PAIRS sValues;
if (phrase_parse(pIter, pEnd, sGrammar, boost::spirit::ascii::space, sValues) && pIter == pEnd) {
std::cerr << "parsing successful!" << std::endl;
for (const auto &r : sValues)
std::cout << r.first << "=" << std::scientific << std::setprecision(2) << r.second << std::endl;
} else {
std::cerr << "parsing failed!" << std::endl;
std::cerr << std::quoted(std::string(pIter, pEnd)) << std::endl;
}
}
还请注意常规改进,例如将调试添加到规则中。