如何绕过贪婪的道路

How to get around greedy rd?

本文关键字:道路 贪婪 何绕过      更新时间:2023-10-16

我想解析一个可以包含'-'的字符串,但不能以它开头或结尾。

我希望这个解析器可以工作:

auto const parser = alnum >> -(*(alnum | char_('-')) >> alnum);

但是在我的测试输入"某物"中,它只解析"所以",而不会吃掉其余的。

问题是中间位*(alnum | char_('-'))一直吃到最后(包括最后一个字符,所以整个可选括号都失败了(。

如何以及为什么在这里和这里解释

想知道的是,我怎样才能绕过它并制作这个解析器?

现场观看:http://coliru.stacked-crooked.com/a/833cc2aac7ba5e27

我个人会"积极"地写它:

auto const rule = raw [ lexeme [
    alnum >> *('-' >> alnum | alnum) >> !(alnum|'-') 
] ];

这使用

  • lexeme处理空格意义,
  • raw避免主动匹配要作为输出一部分的每个字符(您只需要所有字符(。
  • '-' >> alnum积极要求任何破折号后面都有一个alnum。请注意,这也禁止在输入中"--"。请参阅下面的变体

住在科里鲁

#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <string>
#include <algorithm>
namespace x3 = boost::spirit::x3;
namespace parser {
    using namespace boost::spirit::x3;
    auto const rule = raw [ lexeme [
        alnum >> *('-' >> alnum | alnum) >> !(alnum|'-') 
    ] ];
}
int main() {
    struct test { std::string input; bool expected; };
    for (auto const t : {
            test { "some-where", true },
            test { " some-where", true },
            test { "some-where ", true },
            test { "s", true },
            test { " s", true },
            test { "s ", true },
            test { "-", false },
            test { " -", false },
            test { "- ", false },
            test { "some-", false },
            test { " some-", false },
            test { "some- ", false },
            test { "some--where", false },
            test { " some--where", false },
            test { "some--where ", false },
        })
    {
        std::string output;
        bool ok = x3::phrase_parse(t.input.begin(), t.input.end(), parser::rule, x3::space, output);
        if (ok != t.expected)
            std::cout << "FAILURE: '" << t.input << "'t" << std::boolalpha << ok << "t'" << output << "'n";
    }
}

变体

为了也允许some--thing和类似的输入,我会将'-'更改为+lit('-')

alnum >> *(+lit('-') >> alnum | alnum) >> !(alnum|'-') 

住在科里鲁

#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <string>
#include <algorithm>
namespace x3 = boost::spirit::x3;
namespace parser {
    using namespace boost::spirit::x3;
    auto const rule = raw [ lexeme [
        alnum >> *(+lit('-') >> alnum | alnum) >> !(alnum|'-') 
    ] ];
}
int main() {
    struct test { std::string input; bool expected; };
    for (auto const t : {
            test { "some-where", true },
            test { " some-where", true },
            test { "some-where ", true },
            test { "s", true },
            test { " s", true },
            test { "s ", true },
            test { "-", false },
            test { " -", false },
            test { "- ", false },
            test { "some-", false },
            test { " some-", false },
            test { "some- ", false },
            test { "some--where", true },
            test { " some--where", true },
            test { "some--where ", true },
        })
    {
        std::string output;
        bool ok = x3::phrase_parse(t.input.begin(), t.input.end(), parser::rule, x3::space, output);
        if (ok != t.expected)
            std::cout << "FAILURE: '" << t.input << "'t" << std::boolalpha << ok << "t'" << output << "'n";
    }
}

我通过告诉贪婪的 kleene 星内的解析器忽略"eoi"(输入结束(来修复它。一个更强大的修复程序也会让它因空格而失败:

所以*(alnum | char_('-'))变得*((alnum | char_('-')) >> !(eoi | space))

现场观看:http://coliru.stacked-crooked.com/a/79242cdbd2fac947