Свободное определение «разбора» будет означать преобразование текстового представления в «другое» (часто более native ) представление.
В действительности не имеет смысла «разбирать» "число в std :: string. То, что вы видите, это автоматическое c распространение атрибутов, которое очень старается понять его (вставляя проанализированный номер в строку как символ).
Это не то, что вы хотели. Вместо этого вы хотите проанализировать целочисленное значение или двойное значение. Для этого Вы можете просто объявить тип атрибута варианта:
using V = boost::variant<std::string, double, unsigned int>;
qi::rule<std::string::const_iterator, V()>
immediate = double_quoted_string | qi::double_ | qi::uint_;
Вот и все. Демонстрация в реальном времени, добавление проверки типов по результату:
Live On Coliru
#include <iostream>
#include <iomanip>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
using namespace std::string_literals;
int main() {
for (auto&& [str, type] : std::vector {
std::pair("\"hello\""s, typeid(std::string).name()),
{" \" hello \" "s, typeid(std::string).name()},
{" \" hello \"\"stranger\"\" \" "s, typeid(std::string).name()},
{"1"s, typeid(unsigned int).name()},
{"23"s, typeid(unsigned int).name()},
{"456"s, typeid(unsigned int).name()},
{"3.3"s, typeid(double).name()},
{"34.35"s, typeid(double).name()},
}) {
auto iter = str.cbegin(), end = str.cend();
qi::rule<std::string::const_iterator, std::string()> double_quoted_string
= '"' >> *("\"\"" >> qi::attr('"') | ~qi::char_('"')) >> '"';
using V = boost::variant<std::string, double, unsigned int>;
qi::rule<std::string::const_iterator, V()> immediate
= double_quoted_string | qi::double_ | qi::uint_;
std::cout << std::quoted(str) << " ";
V res;
bool r = qi::phrase_parse(iter, end, immediate, qi::blank, res);
bool typecheck = (type == res.type().name());
if (r) {
std::cout << "OK: " << res << " typecheck " << (typecheck?"MATCH":"MISMATCH") << "\n";
} else {
std::cout << "Failed\n";
}
if (iter != end) {
std::cout << "Remaining unparsed: " << std::quoted(std::string(iter, end)) << "\n";
}
std::cout << "----\n";
}
}
Печать
"\"hello\"" OK: hello typecheck MATCH
----
" \" hello \" " OK: hello typecheck MATCH
----
" \" hello \"\"stranger\"\" \" " OK: hello "stranger" typecheck MATCH
----
"1" OK: 1 typecheck MISMATCH
----
"23" OK: 23 typecheck MISMATCH
----
"456" OK: 456 typecheck MISMATCH
----
"3.3" OK: 3.3 typecheck MATCH
----
"34.35" OK: 34.35 typecheck MATCH
----
Обратите внимание на изменение порядка uint_
после double_
. Если вы сначала анализируете целые числа, он будет анализировать целую часть двойного числа до десятичного разделителя, а затем не сможет проанализировать остальные. Чтобы быть более точным, вы можете использовать строгий реальный синтаксический анализатор, так что только число, которое имеет дробь, будет проанализировано как двойные числа. Это действительно ограничивает диапазон для целых чисел, потому что unsigned int
имеет гораздо меньший диапазон, чем double
.
См. Parse int или double с использованием Boost Spirit (longest_d)
Live On Coliru
qi::rule<std::string::const_iterator, V()> immediate
= double_quoted_string
| qi::real_parser<double, qi::strict_real_policies<double> >{}
| qi::uint_;
Печать
"\"hello\"" OK: hello typecheck MATCH
----
" \" hello \" " OK: hello typecheck MATCH
----
" \" hello \"\"stranger\"\" \" " OK: hello "stranger" typecheck MATCH
----
"1" OK: 1 typecheck MATCH
----
"23" OK: 23 typecheck MATCH
----
"456" OK: 456 typecheck MATCH
----
"3.3" OK: 3.3 typecheck MATCH
----
"34.35" OK: 34.35 typecheck MATCH
----