c++ - 如何编写 boost::spirit::qi 解析器来执行 '?' 在正则表达式中所做的事情?

标签 c++ regex boost-spirit backtracking qi

假设我们有一个正则表达式“start:(?: ([0-9]{1,2}))? ([0-9].*)”。

它会匹配

std::string string1 = "start: 01 0ab";

std::string string2 = "start: 0ab";

我们也可以分别得到2个匹配的字符串。

我尝试使用 boost::spirit::qi 解析器来解析 string2 但它无法匹配。

qi::rule<std::string::const_iterator, std::string()> rule1 = qi::repeat(1,2)[qi::digit];
qi::rule<std::string::const_iterator, std::string()> rule2 = qi::digit >> *qi::char_;
std::vector<std::string> attr;
auto it_begin = string2.begin();
auto it_end = string2.end();
if (qi::parse(
    it_begin,
    it_end,
    qi::lit("start:")
         >> -(qi::lit(" ") >> rule1)
         >> qi::lit(" ") >> rule2
         >> qi::eoi,
    attr))
    std::cout<<"match"<<std::endl;
else
    std::cout<<"not match"<<std::endl;

我们当然可以使用前瞻运算符来检查规则1后面的内容,但是是否有更通用的方法来实现正则表达式运算符“?” ?谢谢!

最佳答案

我不确定这个期望有什么问题。对于其他不明确的规则来说,这是唯一的方法,因为 PEG 语法总是贪婪的。

但是,也许您没有达到最优雅的形式,因为您正在寻找“更好”的东西。这就是我要做的。

我会使用船长来匹配空格:

    if (qi::phrase_parse(it_begin, it_end,
                "start:" >> -rule1 >> rule2 >> qi::eoi,
                qi::space, attr))

其中规则仍然是词位(因为没有船长就声明了):

qi::rule<It, std::string()> const 
    rule1 = qi::digit >> qi::digit >> &qi::space,
    rule2 = qi::digit >> *qi::graph;

Note qi::graph doesn't match whitespace, where *qi::char_ simply matches anything at all greedily.

Live On Coliru

#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;

int main() {
    using It = std::string::const_iterator;

    // implicitly lexemes (no skipper in rule declaration)
    qi::rule<It, std::string()> const 
        rule1 = qi::digit >> qi::digit >> &qi::space,
        rule2 = qi::digit >> *qi::graph;

    for (std::string const input : { "start: 01 0ab", "start: 0ab", }) {
        std::vector<std::string> attr;

        auto it_begin = input.begin();
        auto it_end   = input.end();

        if (qi::phrase_parse(it_begin, it_end, "start:" >> -rule1 >> rule2 >> qi::eoi, qi::space, attr))
            std::cout << "match\n";
        else
            std::cout << "not match\n";

        if (it_begin!=it_end)
            std::cout<<"Remaining unparsed input: '" << std::string(it_begin, it_end) << "'\n";
    }
}

打印

match
match

¹ 这假设多个/不同的空白是可以的。如果换行符不应算作空格,请使用 qi::blank 而不是 qi::space

关于c++ - 如何编写 boost::spirit::qi 解析器来执行 '?' 在正则表达式中所做的事情?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40043636/

相关文章:

c++ - 将指向基类型的指针与派生类型的指针进行比较

c++ - Boost Spirit 和抽象语法树设计

c++ - 使用 boost-spirit 解析简单的 csv 表

c++ - 如何使用 boost 在 QI 解析过程中对数字进行舍入?

c++ - 在 C++ 中使用正则表达式查找 [/和 ] 之间的数字

c++ - 点燃 C++ : serialization class not found in cache store

c++ - boost::asio::ssl 多线程应用程序访问冲突

javascript - 用正则表达式解释 javascript 代码

ruby - 用长字符串替换

正则表达式:如果宽度或高度小于 100px,则匹配 <img> 标记