正在分析BoostSpirit中固定列表中的选择
Parsing selections from a fixed list in Boost.Spirit
从员工开始-解析成结构示例:
template <typename Iterator>
struct employee_parser : qi::grammar<Iterator, employee(), ascii::space_type>
{
employee_parser() : employee_parser::base_type(start)
{
using qi::int_;
using qi::lit;
using qi::double_;
using qi::lexeme;
using ascii::char_;
quoted_string %= lexeme['"' >> +(char_ - '"') >> '"'];
start %=
lit("employee")
>> '{'
>> int_ >> ','
>> quoted_string >> ','
>> quoted_string >> ','
>> double_
>> '}'
;
}
qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
qi::rule<Iterator, employee(), ascii::space_type> start;
};
假设我想用一个匹配存储在给定容器中的任何字符串的规则来替换quoted_string
。
例如,如果我有一个容器,例如:
std::array<std::string, 4> match_list =
{ "string0", "string1", "string2", "string3" };
我希望解析器只将输入与数组中的一个值匹配(容器不必是数组(。
我相信这很简单,但Spirit帮助页面似乎并没有解决这个问题。
它很简单:https://www.boost.org/doc/libs/1_67_0/libs/spirit/doc/html/spirit/qi/reference/string/symbols.html
在Coliru上直播
#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 failedn";
}
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")
;
打印在Coliru上直播
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)
;
打印Coliru
Parsed: (42;3;more names or stuff;6.7)
最后,您可以使用raw[]
来"转换"输入序列,例如与qi::no_space[]
:LiveOnColiru组合
>> raw[no_case[symbol_]] >> ','
打印
Parsed: (42;sTrInG3;more names or stuff;6.7)
赛斯在评论中鼓励我也发布我的答案后,它就在这里了。正如预期的那样,它非常相似,只是我从传递给语法的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
相关文章:
- 如何(从固定列表中)选择一个数字序列,该序列将与目标数字相加
- 列表视图更改选择颜色
- 如何使用cpp编写选择排序算法以降序对元素列表进行排序?
- 正在分析BoostSpirit中固定列表中的选择
- 如何修复列表视图中的错误?,封装控件时无法选择任何项
- 如何在C++中创建数字列表,以便它可以选择一个随机数?
- 带有选择的菜单列表
- 在修改项目列表时,请防止可编辑的Qcombobox选择更改
- 为 STL 列表编写选择排序
- 如何从图形的邻接列表表示中随机选择边缘
- 如何根据MFC中的列表控制选择禁用按钮
- 如何使gotoxy()函数在光标所在的链接列表中选择节点
- 未选择引用到数组的构造函数进行列表初始化
- 如何选择第二个列表框
- C++ 在列表和列表之间选择返回类型<<string>std::p air<string,string>>
- 从有限列表进行简单选择
- 使用值为 std::shared_ptr的映射是具有多索引类列表的良好设计选择
- SQLite:通过100K元素列表选择IN
- 从列表小部件中选择并添加到文本编辑
- 为我的玩家列表选择最佳结构