c++ - Boost::qi 解析字符串
问题描述
我需要从下一个 hls 标签中解析“title”
标签的模式:#EXTINF:<duration>[,<title>]
以真实标签为例:
#EXTINF:10,Title of the segment => I need "Title of the segment" phrase
#EXTINF:20,Title => I need "Title" phrase
#EXTINF:12 => I need "" phrase
我写了下一个代码
double duration;
std::string title;
boost::spirit::qi::rule<Iterator, std::string()> quoutedString;
quoutedString %= lexeme[+(char_)];
bool r = parse(first, last,
("#EXTINF:" >> double_[ref(duration) = _1] >> -(',' >> quoutedString[ref(title) = _1] ) )
);
if (!r || first != last) {
addMinorProblem(stateObj, _("Cannot parse information from #EXTINF tag"));
return false;
}
但是我在编译过程中遇到了下一个错误:
error: call of overloaded ‘ref(std::__cxx11::string&)’ is ambiguous
("#EXTINF:" >> double_[ref(duration) = _1] >> -(',' >> quoutedString[ref(title) = _1] ) )
请帮我。我究竟做错了什么?
解决方案
您使用的命名空间太多了。此外,ADL无论如何std::ref
都会引入std::string
参数,除非ref
是带括号的或命名空间限定的。
过度使用using namespace
is 从来都不是一个好主意(参见例如为什么“使用命名空间 std;”被认为是不好的做法?std::ref
),在这种情况下,该消息说明了and之间的混淆boost::phoenix::ref
(以及可能的其他人,但您没有包括完整的消息)。
拒绝吧:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/optional.hpp>
#include <iomanip>
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
#define addMinorProblem(...) do {} while (0)
boost::optional<std::pair<double, std::string>> parse(std::string_view input)
{
using Iterator = std::string_view::const_iterator;
Iterator first = begin(input), last = end(input);
double duration;
std::string title;
boost::spirit::qi::rule<Iterator, std::string()> quoutedString;
quoutedString %= qi::lexeme[+(qi::char_)];
bool r = parse(first, last,
("#EXTINF:" >> qi::double_[px::ref(duration) = qi::_1] >>
-(',' >> quoutedString[px::ref(title) = qi::_1])));
if (!r || first != last) {
addMinorProblem(stateObj,
_("Cannot parse information from #EXTINF tag"));
return {};
}
return std::make_pair(duration, title);
}
int main()
{
for (std::string const input : {
"#EXTINF:10,Title of the segment", // => I need "Title of the
// segment" phrase
"#EXTINF:20,Title", // => I need "Title" phrase
"#EXTINF:12", // => I need "" phrase
}) {
if (auto result = parse(input)) {
std::cout << "Parsed: (" << result->first << ", " << std::quoted(result->second) << ")\n";
} else {
std::cout << "Cannot parse " << std::quoted(input) << "\n";
}
}
}
印刷
Parsed: (10, "Title of the segment")
Parsed: (20, "Title")
Parsed: (12, "")
改善,小事
通过一些明智的本地using 声明,您可以再次使其“更短”:
using namespace qi::labels; using px::ref; bool r = parse(first, last, ("#EXTINF:" >> qi::double_[ref(duration) = _1] >> -(',' >> quoutedString[(ref)(title) = _1])));
我个人觉得这更晦涩难懂(想象自己
(ref)(title)
在代码审查中解释?)operator %=
没有语义动作是没有意义的qi::lexeme[]
没有船长就毫无意义(请参阅Boost Spirit 船长问题)quoutedString
[原文如此]用词不当(现在?)因为它不解析引号为什么不使用自动属性传播而不是痛苦的语义操作?它们只会增加编译时间,而且,正如您所发现的,还会增加开发时间。参见Boost Spirit:“语义行为是邪恶的”?
first == last
另外,与其在解析后进行繁琐的检查,不如简单地匹配>> qi::eoi
表达式?
以上所有内容都简化为以下内容:
boost::optional<std::pair<double, std::string>> parse(std::string_view input)
{
namespace qi = boost::spirit::qi;
double duration;
std::string title;
if (qi::parse(
begin(input), end(input), //
("#EXTINF:" >> qi::double_ >> -(',' >> +qi::char_) >> qi::eoi),
duration, title))
{
return std::make_pair(duration, title);
}
addMinorProblem(stateObj, _("Cannot parse information from #EXTINF tag"));
return {};
}
没有更多phoenix
,语义动作,什么不是。仍在打印:
Parsed: (10, "Title of the segment")
Parsed: (20, "Title")
Parsed: (12, "")
推荐阅读
- r - 强制 ggsave 对 .wmf 文件中的点几何图形进行矢量化
- vue-cli - 为 vue cli 运行服务时没有可用的开放端口是我要求的
- javascript - 制作 Spring form:select 可通过两个参数搜索
- tensorflow - Tensorflow Hub 与 Keras 应用程序 - 性能下降
- r - 计算 R 矩阵中每列特定整数的数量
- python-3.x - 通知设备应用程序进行设备孪生更新(python)
- javascript - 反应:改变状态 onMouseOver
- vba - 从查询中提取多个电子邮件地址以自动访问电子邮件?
- python - 用 LightGBM 制作 CART / RF 的超参数
- python - Django - Receiving error "too many values to unpack (expected 2)"