四、行动

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

Example 11.9. Linking actions with parsers

#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iostream>using namespace boost::spirit;int main()
{std::string s;std::getline(std::cin, s);auto it = s.begin();bool match = qi::phrase_parse(it, s.end(),qi::int_[([](int i){ std::cout << i << '\n'; })], ascii::space);std::cout << std::boolalpha << match << '\n';if (it != s.end())std::cout << std::string{it, s.end()} << '\n';
}

示例 11.9 使用 boost::spirit::qi::int_ 解析一个整数,然后将该整数写入标准输出。这就是为什么一个动作与 boost::spirit::qi::int_ 相关联。动作是应用解析器时调用的函数或函数对象。链接是使用运算符 operator[] 完成的,它被 boost::spirit::qi::int_ 和其他解析器重载。示例 11.9 使用 lambda 函数作为操作,该操作需要一个 int 类型的唯一参数并将其写入标准输出。

如果您启动示例 11.9 并输入一个数字,则会显示该数字。

传递给动作的参数类型取决于解析器。例如, boost::spirit::qi::int_ 转发一个 int 值,而 boost::spirit::qi::float_ 传递一个 float 值。

Example 11.10. Boost.Spirit with Boost.Phoenix

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/phoenix/phoenix.hpp>
#include <string>
#include <iostream>using namespace boost::spirit;
using boost::phoenix::ref;int main()
{std::string s;std::getline(std::cin, s);auto it = s.begin();int i;bool match = qi::phrase_parse(it, s.end(), qi::int_[ref(i) = qi::_1],ascii::space);std::cout << std::boolalpha << match << '\n';if (match)std::cout << i << '\n';if (it != s.end())std::cout << std::string{it, s.end()} << '\n';
}

示例 11.10 使用 Boost.Phoenix 将使用 boost::spirit::qi::int_ 解析的 int 值存储在 i 中。如果 boost::spirit::qi::phrase_parse() 返回 true,则将 i 写入标准输出。

这个例子在包含来自 Boost.Spirit 的头文件之前定义了宏 BOOST_SPIRIT_USE_PHOENIX_V3。此宏选择 Boost.Phoenix 的第三个和当前版本。这很重要,因为 Boost.Phoenix 是从 Boost.Spirit 派生的,而 Boost.Spirit 包含 Boost.Phoenix 的第二个版本。如果未定义 BOOST_SPIRIT_USE_PHOENIX_V3,则 Boost.Phoenix 的第二个版本将包含在 Boost.Spirit 头文件中,第三个版本将包含在 boost/phoenix/phoenix.hpp 中。不同的版本会导致编译器错误。

请注意如何详细定义 lambda 函数。 boost::phoenix::ref() 创建对变量 i 的引用。但是,占位符 _1 不是来自 Boost.Phoenix,而是来自 Boost.Spirit。这很重要,因为 boost::spirit::qi::_1 提供了对具有通常预期类型的​​解析值的访问——示例 11.10 中的 int。如果 lambda 函数使用 boost::phoenix::placeholders::arg1,编译器会报错,因为 boost::phoenix::placeholders::arg1 不代表 int;它将基于 Boost.Spirit 中的另一种类型,并且需要提取 int 值。

五、属性

操作是处理解析值的一种选择。另一种选择是将对象传递给 boost::spirit::qi::parse() 或 boost::spirit::qi::phrase_parse() 用于存储解析值。这些对象称为属性。它们的类型必须与解析器的类型相匹配。

您已经在上一节中使用过属性。传递给动作的参数也是属性。每个解析器都有一个属性。例如,解析器 boost::spirit::qi::int_ 具有 int 类型的属性。在以下示例中,属性不会作为参数传递给函数。相反,解析后的值存储在属性中,可以在 boost::spirit::qi::parse() 或 boost::spirit::qi::phrase_parse() 返回后处理。

Example 11.11. Storing an int value in an attribute

#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iostream>using namespace boost::spirit;int main()
{std::string s;std::getline(std::cin, s);auto it = s.begin();int i;if (qi::phrase_parse(it, s.end(), qi::int_, ascii::space, i))std::cout << i << '\n';
}

示例 11.11 使用解析器 boost::spirit::qi::int_。解析后的 int 值存储在变量 i 中。 i 作为另一个参数传递给 boost::spirit::qi::phrase_parse(),因此成为解析器 boost::spirit::qi::int_ 的一个属性。 如果您启动示例 11.11 并输入一个数字,该数字将被写入标准输出流。

Example 11.12. Storing several int values in an attribute

#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();std::vector<int> v;if (qi::phrase_parse(it, s.end(), qi::int_ % ',', ascii::space, v)){std::ostream_iterator<int> out{std::cout, ";"};std::copy(v.begin(), v.end(), out);}
}

示例 11.12 使用了一个用 qi::int_ % ',' 定义的解析器。解析器接受由逗号分隔的任意数量的整数。像往常一样忽略空格。

因为解析器可以返回多个 int 值,所以属性的类型必须支持存储多个 int 值。该示例传递一个向量。如果您开始该示例并输入多个以逗号分隔的整数,则这些整数将写入以分号分隔的标准输出流。

除了向量,您还可以传递其他类型的容器,例如 std::list。Boost.Spirit 文档描述了哪些属性类型必须与哪些运算符一起使用。

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

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

    五.rule规则 在 Boost.Spirit 中,解析器由规则组成.由于规则通常基于 Boost.Spirit 提供的解析器,因此没有明显的区别.例如, boost::spirit::ascii:: ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  9. 字符串相关处理kmp,前缀数,后缀树,后缀数组,最长回文串,最长重复字串,最长非重复字串

    1. 最长回文串 一般用后缀数组或者后缀树可以解决, 用此方法:http://blog.csdn.net/v_july_v/article/details/6897097 预处理后缀树,使得查询LCA ...

最新文章

  1. NVIDIA GPUs上深度学习推荐模型的优化
  2. 从责任界定和问题预警角度 解读全栈溯源对DevOps的价值
  3. hadoop2.2.0安装,完全分布式安装
  4. JAVA关系表达式解析微引擎
  5. linux查看上次重启日志和ip,Linux實時查看日志,訪問前10IP 和相關命令
  6. 绑定到对象上的copyWithin方法
  7. 指点聚源码论坛全站源码 WordPress内核
  8. Linux Shell脚本入门教程系列之(八)Shell printf命令详解
  9. 【英语学习】【WOTD】newspeak 释义/词源/示例
  10. iphone11右上角信号显示_iOS 11信号显示栏变了!这意味着啥?
  11. IOS UIScrollView中 使用 touch 无法响应的问题
  12. linux 编译 pascal,免费开源的Pascal编译器 GNU Pascal
  13. [Video Transformer] VTN: Video Transformer Network
  14. Android 开发第七弹:简易时钟(秒表)
  15. Windows环境下使用GTK
  16. ASO小技能:自动输入搜索框文本
  17. 百度搜索技术沙龙感悟
  18. vue网页预加载页面_页面预加载效果
  19. namespace 命名空间
  20. 基于国密算法实现主机之间的密钥分发和安全传输-2021西北工业大学网络空间安全学院暑期夏令营

热门文章

  1. 机器学习模型选择:调参参数选择
  2. Hdoj 2671 Can't be easier
  3. 简单好用的音频转换器分享
  4. jedispool 为redis保驾护航
  5. 计算机网络 自顶向下方法 学习笔记 第一章
  6. TLS1之__thread
  7. 计算机软件侵权鉴定,通过计算机软件侵权司法鉴定简要对比流程看软件侵权对比方法...
  8. python全排列,递归
  9. 《高效能人士的7个习惯》——习惯三:要事第一 之 独立意志的重要性
  10. Python环境迁移