五、rule规则

在 Boost.Spirit 中,解析器由规则组成。由于规则通常基于 Boost.Spirit 提供的解析器,因此没有明显的区别。例如, boost::spirit::ascii::digit 既可以是解析器,也可以是规则。通常,规则指的是更复杂的表达式,例如 qi::int_ % ','。

在迄今为止的所有示例中,规则都直接传递给 boost::spirit::qi::parse() 或 boost::spirit::qi::phrase_parse()。通过 boost::spirit::qi::rule,Boost.Spirit 提供了一个类来定义规则变量。例如,如果应该将规则存储在类的成员变量中,则需要 boost::spirit::qi::rule。

Example 11.13. Defining rules with boost::spirit::qi::rule

#include <boost/spirit/include/qi.hpp>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <iostream>using namespace boost::spirit;int main()
{std::string s;std::getline(std::cin, s);auto it = s.begin();qi::rule<std::string::iterator, std::vector<int>(),ascii::space_type> values = qi::int_ % ',';std::vector<int> v;if (qi::phrase_parse(it, s.end(), values, ascii::space, v)){std::ostream_iterator<int> out{std::cout, ";"};std::copy(v.begin(), v.end(), out);}
}

示例 11.13 的工作方式与示例 11.12 类似。如果您输入多个以逗号分隔的整数,它们将用分号显示。与前面的示例相比,解析器没有直接传递给 boost::spirit::qi::phrase_parse(),而是在 boost::spirit::qi::rule 变量中定义。

boost::spirit::qi::rule 是一个类模板。唯一的强制参数是被解析字符串的迭代器类型。在示例中,还传递了另外两个可选模板参数。

第二个模板参数是 std::vector<int>(),它是返回 std::vector<int> 类型向量且不需要参数的函数的签名。该模板参数表示解析的属性类型为int向量。

第三个模板参数是 boost::spirit::qi::phrase_parse() 使用的 skipper 的类型。在示例中,使用了船长 boost::spirit::ascii::space。该船长的类型可通过 boost::spirit::ascii::space_type 获得,并作为模板参数传递给 boost::spirit::qi::rule。

如果您希望您的代码独立于平台并使用 C++11 开发环境,您应该更喜欢 boost::spirit::qi::rule 而不是关键字 auto。如果值是用 auto 定义的,则该示例在 GCC 和 Clang 中可以正常工作。然而,在 Visual C++ 2013 中,只有第一个数字被解析并写入标准输出。

Example 11.14. Nesting Rules

#include <boost/spirit/include/qi.hpp>
#include <boost/variant.hpp>
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>using namespace boost::spirit;struct print : public boost::static_visitor<>
{template <typename T>void operator()(T t) const{std::cout << std::boolalpha << t << ';';}
};int main()
{std::string s;std::getline(std::cin, s);auto it = s.begin();qi::rule<std::string::iterator, boost::variant<int, bool>(),ascii::space_type> value = qi::int_ | qi::bool_;qi::rule<std::string::iterator, std::vector<boost::variant<int, bool>>(),ascii::space_type> values = value % ',';std::vector<boost::variant<int, bool>> v;if (qi::phrase_parse(it, s.end(), values, ascii::space, v)){for (const auto &elem : v)boost::apply_visitor(print{}, elem);}
}

Example 11.14. Nesting Rules

#include <boost/spirit/include/qi.hpp>
#include <boost/variant.hpp>
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>using namespace boost::spirit;struct print : public boost::static_visitor<>
{template <typename T>void operator()(T t) const{std::cout << std::boolalpha << t << ';';}
};int main()
{std::string s;std::getline(std::cin, s);auto it = s.begin();qi::rule<std::string::iterator, boost::variant<int, bool>(),ascii::space_type> value = qi::int_ | qi::bool_;qi::rule<std::string::iterator, std::vector<boost::variant<int, bool>>(),ascii::space_type> values = value % ',';std::vector<boost::variant<int, bool>> v;if (qi::phrase_parse(it, s.end(), values, ascii::space, v)){for (const auto &elem : v)boost::apply_visitor(print{}, elem);}
}

example11.14 定义了两个规则,其中一个引用另一个:values 定义为 value % ',',value 设置为 qi::int_ | qi::bool_。 values 表示可以解析由逗号分隔的任意数量的值。 value 将值定义为整数或布尔值。总之,规则规定用逗号分隔的整数和布尔值可以按任何顺序输入。

为了存储任意数量的值,提供了一个 std::vector 类型的容器。因为值的类型是 int 或 bool,所以需要一个可以存储 int 或 bool 值的类。根据属性类型和运算符的概述,必须使用来自 Boost.Variant 的类 boost::variant。

如果您启动示例并输入以逗号分隔的整数和布尔值,则这些值将写入以分号分隔的标准输出流。这是在 Boost.Variant 提供的函数 boost::apply_visitor() 的帮助下完成的。这个函数需要一个访问者——在这个例子中是类 print 的一个对象。

请注意,布尔值必须输入为 true 和 false。

六、语法

如果要解析复杂的格式,需要定义多个相互引用的规则,可以用 boost::spirit::qi::grammar 进行分组。

Example 11.15. Grouping rules in a grammar

#include <boost/spirit/include/qi.hpp>
#include <boost/variant.hpp>
#include <string>
#include <vector>
#include <iostream>using namespace boost::spirit;template <typename Iterator, typename Skipper>
struct my_grammar : qi::grammar<Iterator,std::vector<boost::variant<int, bool>>(), Skipper>
{my_grammar() : my_grammar::base_type{values}{value = qi::int_ | qi::bool_;values = value % ',';}qi::rule<Iterator, boost::variant<int, bool>(), Skipper> value;qi::rule<Iterator, std::vector<boost::variant<int, bool>>(), Skipper>values;
};struct print : public boost::static_visitor<>
{template <typename T>void operator()(T t) const{std::cout << std::boolalpha << t << ';';}
};int main()
{std::string s;std::getline(std::cin, s);auto it = s.begin();my_grammar<std::string::iterator, ascii::space_type> g;std::vector<boost::variant<int, bool>> v;if (qi::phrase_parse(it, s.end(), g, ascii::space, v)){for (const auto &elem : v)boost::apply_visitor(print{}, elem);}
}

示例 11.15 的工作方式与示例 11.14 类似:您可以按任何顺序输入整数和布尔值,并以逗号分隔。它们将以相同的顺序写入标准输出流,但用分号分隔。该示例使用与前一个相同的规则——值和值。然而,这一次规则被分组在一个语法中。语法在一个名为 my_grammar 的类中定义,该类派生自 boost::spirit::qi::grammar。

my_grammar 和 boost::spirit::qi::grammar 都是类模板。 boost::spirit::qi::grammar 期望的模板参数与 boost::spirit::qi::rule 期望的模板参数相同。要解析的字符串的迭代器类型必须传递给 boost::spirit::qi::grammar。您还可以传递定义属性类型和船长类型的函数的签名。

在 my_grammar 中, boost::spirit::qi::rule 用于定义规则值和值。规则被定义为成员变量并在构造函数中初始化。

请注意,最外层的规则必须与 base_type 一起传递给基类的构造函数。这样,Boost.Spirit 就知道哪个规则是语法的入口点。

一旦定义了语法,就可以像解析器一样使用它。在示例 11.15 中,my_grammar 在 main() 中实例化以创建 g。然后将 g 传递给 boost::spirit::qi::phrase_parse()。

Example 11.16. Storing parsed values in structures

#include <boost/spirit/include/qi.hpp>
#include <boost/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <string>
#include <vector>
#include <iostream>using namespace boost::spirit;typedef boost::variant<int, bool> int_or_bool;struct int_or_bool_values
{int_or_bool first;std::vector<int_or_bool> others;
};BOOST_FUSION_ADAPT_STRUCT(int_or_bool_values,(int_or_bool, first)(std::vector<int_or_bool>, others)
)template <typename Iterator, typename Skipper>
struct my_grammar : qi::grammar<Iterator, int_or_bool_values(), Skipper>
{my_grammar() : my_grammar::base_type{values}{value = qi::int_ | qi::bool_;values = value >> ',' >> value % ',';}qi::rule<Iterator, int_or_bool(), Skipper> value;qi::rule<Iterator, int_or_bool_values(), Skipper> values;
};struct print : public boost::static_visitor<>
{template <typename T>void operator()(T t) const{std::cout << std::boolalpha << t << ';';}
};int main()
{std::string s;std::getline(std::cin, s);auto it = s.begin();my_grammar<std::string::iterator, ascii::space_type> g;int_or_bool_values v;if (qi::phrase_parse(it, s.end(), g, ascii::space, v)){print p;boost::apply_visitor(p, v.first);for (const auto &elem : v.others)boost::apply_visitor(p, elem);}
}

示例 11.16 基于前面的示例,但需要至少两个值。规则值定义为 value >> ',' >> value % ','。

values 中的第一个组件是 value,第二个是 value % ','。第一个组件解析的值必须存储在 boost::variant 类型的对象中。第二个组件解析的值必须存储在容器中。使用 int_or_bool_values,该示例提供了一个结构来存储由规则值的两个组件解析的值。

要将 int_or_bool_values 与 Boost.Spirit 一起使用,必须使用宏 BOOST_FUSION_ADAPT_STRUCT。该宏由 Boost.Fusion 提供。该宏可以将 int_or_bool_values 视为具有 int_or_bool 和 std::vector<int_or_bool> 类型的两个值的元组。因为这个元组具有正确数量的正确类型的值,所以可以使用签名 int_or_bool_values() 定义值。 values 将在 first 中存储第一个解析值,在其他中存储所有其他解析值。

int_or_bool_values 类型的对象作为属性传递给 boost::spirit::qi::phrase_parse()。如果您启动示例并输入至少两个以逗号分隔的整数或布尔值,则它们都存储在属性中并写入标准输出流。

解析器已从上一个示例中使用的内容进行了更改。如果值是用 value % ',' 定义的,则 int_or_bool_values 将只有一个成员变量,并且所有解析的值都可以存储在一个向量中,如前面的示例所示。因此,int_or_bool_values 就像一个只有一个值的元组——Boost.Spirit 不支持。只有一个成员变量的结构将导致编译器错误。该问题有多种解决方法。

练习
        创建一个可以加减整数的解析器。解析器应该能够处理像 1+2-5+8 这样的输入,并将结果(这里是 6)写入标准输出。

扩展您的解析器:它现在应该也支持浮点数。此外,应该可以使用分数。新的解析器应该能够处理像 1.2+6/5-0.9 这样的输入,并且应该将结果(这里是 1.5)写入标准输出。

【BOOST C++字串专题11】Boost.Spirit(三)相关推荐

  1. 【BOOST C++字串专题11】Boost.Spirit(一)

    目录 一.Boost.Spirit库介绍 二. boost::spirit::qi::parse()解析格式 三.解析器 一.Boost.Spirit库介绍 本章介绍库 Boost.Spirit. B ...

  2. 【BOOST C++字串专题11】Boost.Spirit(二)

    四.行动 到目前为止,本章中的示例只检测到两件事:解析器是否成功以及解析器在哪里结束.但是,解析器通常以某种方式处理数据,正如您将在下一个示例中看到的那样. Example 11.9. Linking ...

  3. LeetCode中等题之无重复字符的最长字串

    题目 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度. 示例 1: 输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 &q ...

  4. C++11 boost::spirit::qi简单的XML解析器示例

    boost::spirit::qi是一个简单的解释器开发库.可以用来解析文本,构建解释器等. 笔者花了两天时间看完了README文档,并且照着Demo代码写了一遍.感觉语法很复杂.特别是最后的一个XM ...

  5. boost库学习随记五 Boost.Locale 之字符转换 gbk utf8 big5 string wstring等

    Boost.Locale是一个库,它提供高质量的本地化的设施在C + +的方式.它最初是设计的一部分CppCMS - C + +的Web框架的项目,然后促成了提升. Boost.Locale提供强大的 ...

  6. 高效操作字串的String Reference类

    如下面的代码中一个函数接受一个std::string常量引用,在其函数内部需要使用std::string的一些函数操作字串. void foo(const std::string& param ...

  7. Alibaba笔试题:根据关键字求最短摘要字串

    Alibaba笔试题:给定一段产品的英文描述,包含M个英文字母,每个英文单词以空格分隔,无其他标点符号:再给定N个英文单词关键字,请说明思路并编程实现方法String extractSummary(S ...

  8. boost源码剖析之:boost::multi_array

    boost源码剖析之:boost::multi_array 谢轩 刘未鹏 C++的罗浮宫(http://blog.csdn.net/pongba) Note: 并非新作,是以前和老朋友谢轩写的,也可以 ...

  9. 蓝桥杯_算法训练_字串统计

    其实题目已经给的很清楚了,枚举所有的情况,统计出现次数,找到符合条件的结果. 那么我们就根据这个提示完成即可: 第一步:枚举所有可能的字串: 1 #include<iostream> 2 ...

最新文章

  1. python3 生成随机数、随机字符串
  2. python小游戏编程实例-10分钟教你用Python写一个贪吃蛇小游戏,适合练手项目
  3. 【数字信号处理】傅里叶变换性质 ( 傅里叶变换频移性质示例 )
  4. AAAI 2019 | 借鉴传染病学原理探索医学图像CNN可解释性
  5. 电子工程师:不停改方案,神仙都要跑路!
  6. 视频光端机在安防监控工程中的常见技术问题
  7. C 如何对指针进行指定字节的偏置操作
  8. 服务器 发布 WebService 错误
  9. 如何快速查找下载java项目所需jar包
  10. 【java】Thread.start 它是怎么让线程启动的呢
  11. php的email函数发送失败,php中mail函数发送邮件失败的解决方法_php技巧
  12. 七夕抢付限量优惠,全新XPS13二合一笔记本戴尔官网独家首发
  13. 集群分布式存储-MFS
  14. 分布式系统设计系列 -- 基本原理及高可用策略
  15. R语言使用cph函数和rcs函数构建限制性立方样条cox回归模型、使用anova函数进行方差分析通过p值确认指定连续变量和风险值HR之间是否存在非线性关系
  16. python dataframe mean_Python之DataFrame数据处理
  17. java 替换斜杆与反斜杠
  18. HM中CU,TU的划分
  19. 洛克希德马丁可安装在卡车的小型核聚变反应堆10年内诞生
  20. PDF加密软件保护新姿势

热门文章

  1. 小程序使用canvas绘画、签名。wx.canvasToTempFilePath安卓机生成图片背景色为黑色
  2. 一分钟快速将ogg转换成MP3格式
  3. 微信客服接口 报错40003
  4. 喜闻乐见的「手算题」技巧3:巧用 Python
  5. 写代码:假设一年期定期利率为3.25%,计算一下需要过多少年,一万元的一年定期存款连本带息能翻番?...
  6. 编制程序完成下述任务:接受两个数,一个为用 户一年期定期存款金额,一个为按照百分比格式表示的利率;程序计算一年期满后本金与利息总额。说明:(1)存款金额以人民币元为单位,可能精确到分; (2)输入利率
  7. 无线网服务器名字大全,告诉你各个服务器名字的含义
  8. 位(Bit)与字节(Byte)
  9. MySQL面试试题(五)
  10. 关于PHP连接数据库出现:Fatal error: Uncaught Error: Call to undefined function mysql_connect()