从Employee - Parsing into structs示例开始:
quoted_string
假设我想用与存储在给定容器中的任何字符串匹配的规则替换std::array<std::string, 4> match_list =
{ "string0", "string1", "string2", "string3" };
。
例如,如果我有一个容器,例如:
{{1}}
并且我希望解析器仅将输入与数组中的值之一进行匹配(容器不必是数组)。
我确定这很简单,但是Spirit帮助页面似乎无法解决这个问题。
答案 0 :(得分:3)
这很简单:https://www.boost.org/doc/libs/1_67_0/libs/spirit/doc/html/spirit/qi/reference/string/symbols.html
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
struct employee {
int id;
std::string sym;
std::string name;
double value;
};
BOOST_FUSION_ADAPT_STRUCT(employee, id, sym, name, value)
template <typename Iterator, typename Skipper = qi::space_type>
struct employee_parser : qi::grammar<Iterator, employee(), Skipper>
{
employee_parser() : employee_parser::base_type(start)
{
using namespace qi;
quoted_string = lexeme['"' >> +(char_ - '"') >> '"'];
symbol_.add
("string0")
("string1")
("string2")
("string3")
;
start =
lit("employee")
>> '{'
>> int_ >> ','
>> symbol_ >> ','
>> quoted_string >> ','
>> double_
>> '}'
;
}
qi::rule<Iterator, std::string(), Skipper> quoted_string;
qi::rule<Iterator, employee(), Skipper> start;
qi::symbols<char, std::string> symbol_;
};
int main() {
std::string const input = "employee { 42, string3, \"more names or stuff\", 6.7 }";
using It = std::string::const_iterator;
It f = input.begin(), l = input.end();
employee_parser<It> p;
employee e;
if (phrase_parse(f, l, p, qi::space, e)) {
using boost::fusion::operator<<;
std::cout << boost::fusion::tuple_delimiter(';');
std::cout << "Parsed: " << e << "\n";
} else {
std::cout << "Parse failed\n";
}
if (f!=l)
std::cout << "Remaining input: '" << std::string(f,l) << "'\n";
}
打印
Parsed: (42;;more names or stuff;6.7)
要实际包含值:
symbol_.add
("string0", "STRING0")
("string1", "STRING1")
("string2", "STRING2")
("string3", "STRING3")
;
Parsed: (42;STRING3;more names or stuff;6.7)
或者您可以一起使用其他类型:
symbol_.add
("string0", 0)
("string1", 1)
("string2", 2)
("string3", 3)
;
使用
symbol_.add
("string0", 0)
("string1", 1)
("string2", 2)
("string3", 3)
;
Parsed: (42;3;more names or stuff;6.7)
最后,您可以使用raw[]
来“转换”输入序列,例如与qi::no_space[]
结合使用: Live On Coliru
>> raw[no_case[symbol_]] >> ','
打印
Parsed: (42;sTrInG3;more names or stuff;6.7)
答案 1 :(得分:3)
在塞思鼓励我在评论中也张贴我的答案之后,就在这里。正如预期的那样,这与我从传递给语法的std::array
动态构建符号的区别非常相似。
#include <iostream>
#include <string>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
struct employee {
int age;
std::string surname;
std::string forename;
double salary;
};
BOOST_FUSION_ADAPT_STRUCT(employee, age, surname, forename, salary)
namespace ascii = boost::spirit::ascii;
namespace qi = boost::spirit::qi;
template <typename Iterator, std::size_t N>
struct employee_parser : qi::grammar<Iterator, employee(), ascii::space_type> {
employee_parser(std::array<std::string, N> const &match_list)
: employee_parser::base_type(start) {
using namespace qi;
for (auto match : match_list) {
employees.add(match, match);
}
quoted_string %= lexeme['"' >> +(char_ - '"') >> '"'];
start %=
lit("employee")
>> '{'
>> int_ >> ','
>> quoted_string >> ','
>> employees >> ','
>> double_
>> '}'
;
}
qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
qi::rule<Iterator, employee(), ascii::space_type> start;
qi::symbols<typename std::iterator_traits<Iterator>::value_type,
std::string> employees;
};
template <typename Iterator, std::size_t N>
employee parse(Iterator first, Iterator last,
std::array<std::string, N> const &match_list) {
employee_parser<Iterator, N> const grammar(match_list);
employee e;
bool r = qi::phrase_parse(first, last, grammar, ascii::space, e);
if (!r || first != last) {
std::cerr << "Parsing failed at " + std::string(first, last) + "\n";
}
return e;
}
int main() {
employee e;
std::array<std::string, 4> match_list = {"Homer", "Marge", "Lisa", "Bart"};
std::string homer = "employee { 38, \"Simpson\", Homer, 3.0 }";
e = parse(homer.begin(), homer.end(), match_list);
std::cout << "employee { " << e.age << ", " << e.surname << ", "
<< e.forename << ", " << e.salary << " }\n";
// Fails parsing because Hans Mole is not in the list
std::string mole = "employee { 100, \"Mole\", Hans, 0.0 }";
e = parse(mole.begin(), mole.end(), match_list);
std::cout << "employee { " << e.age << ", " << e.surname << ", "
<< e.forename << ", " << e.salary << " }\n";
}
$ clang++ -Wall -Wextra -Wpedantic -std=c++11 test.cpp
$ ./a.out
employee { 38, Simpson, Homer, 3 }
Parsing failed at employee { 100, "Mole", Hans, 0.0 }
employee { 100, Mole, , 0 }
这里也引用荷马的薪水为3.0:https://www.youtube.com/watch?v=HIEWgwRrY9s