【问题标题】:Boost::qi parse stringBoost::qi parse string
【发布时间】:2021-09-09 08:41:03
【问题描述】:

我需要从下一个 hls 标签中解析“title”

标签模式: #EXTINF:[,]

以真实标签为例:

#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] ) )

请帮助我。我做错了什么?

【问题讨论】:

    标签: c++ c++11 boost boost-spirit boost-spirit-qi


    【解决方案1】:

    您过多地使用命名空间。此外,ADL 会为 std::string 参数引入 std::ref,除非 ref 带有括号或命名空间限定。

    过度使用using namespace 绝不是一个好主意(参见例如Why is "using namespace std;" considered bad practice?),在这种情况下,消息说明了std::refboost::phoenix::ref 之间的混淆(可能还有其他人,但你没有' t 包括完整的消息)。

    说不:

    Live On Coliru

    #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, "")
    

    改进,小事

    1. 通过一些明智的 local 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)?)

    2. operator %= 没有语义操作是没有意义的

    3. qi::lexeme[] 没有船长就毫无意义(见Boost spirit skipper issues

    4. quoutedString [sic] 用词不当(现在?),因为它不解析引号

    5. 为什么不使用自动属性传播而不是痛苦的语义操作?它们只会增加编译时间,而且,正如您所发现的,还会增加开发时间。见Boost Spirit: "Semantic actions are evil"?

    6. 另外,与其在解析后繁琐地检查first == last,不如简单地匹配表达式中的&gt;&gt; qi::eoi

    以上所有内容都简化为以下内容:

    Live On Coliru

    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, "")
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多