如何编写一个 boost::spirit::qi 解析器来做'?'在正则表达式中做的事情?

How to write a boost::spirit::qi parser to do what '?' does in regex?

本文关键字:正则表达式 何编写 一个 boost qi spirit      更新时间:2023-10-16

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

它将匹配

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

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

也可以分别得到两个匹配的字符串。

我尝试使用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语法总是贪婪的。

然而,也许你没有得到最优雅的形式,因为你在寻找"更好"的东西。这是我要做的。

我将使用一个skipper来匹配空格¹:

    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;

注意qi::graph不匹配空格,*qi::char_只匹配所有内容。

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 << "matchn";
        else
            std::cout << "not matchn";
        if (it_begin!=it_end)
            std::cout<<"Remaining unparsed input: '" << std::string(it_begin, it_end) << "'n";
    }
}

打印

match
match

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