boost::spirit qi::uint_ 有效号码范围

boost::spirit qi::uint_ valid number range

我想解析由 CC[n] 组成的字符串,其中 1 <= n <= 4 或来自 SERVICE[k],其中 1 <= k <= 63。

有效字符串:“CC1”、“CC2”、“CC3”、“CC4”、“SERVICE1”、“SERVICE2”、...、“SERVICE63”。

我写了下一个表达式:

( '"' >> (qi::raw["CC" >> qi::uint_] | qi::raw["SERVICE" >> qi::uint_]) >> '"' >> qi::eoi)

但是我如何限制 n 和 k?

在输出中,我需要获得完整的字符串 CC1、CC2、... SERVICE63

要限制uint_范围,您可以在语义操作中执行范围检查。例如,它可以作为 lambda 或更简洁地作为 Boost.Phenix 表达式来实现。

The following code 将这些数字解析为向量(省略字符串):

#include <iostream>
#include <string>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>


int main()
{
    std::string input =  "CC1 CC2 CC3 CC4 SERVICE1 SERVICE2";
    std::vector<unsigned int> out;

    using namespace boost::spirit::qi;
    phrase_parse(
        input.begin(), 
        input.end(), 
        *(lexeme[lit("CC") >> uint_ [ _pass = (_1>=1 && _1<=4) ]] | 
        lexeme[lit("SERVICE") >> uint_ [ _pass = (_1>=1 && _1<=63) ]]), 
        ascii::space, 
        out
    );
    for (auto i : out)
        std::cout << i << std::endl;
}

最简单的方法是使用 symbols<>

复杂的方法是验证语义动作中的数字。

我的建议是符号或将语义验证与解析分开(即解析原始数字并在解析后验证 AST)

符号

这可能更灵活、最高效,并且允许您在 AST 域中进行强类型化。它回避了语义操作的编译开销和复杂性:Boost Spirit: "Semantic actions are evil"?

Live On Coliru

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

int main() {
    qi::symbols<char> cc, service;
    cc += "CC1", "CC2", "CC3", "CC4";
    service += "SERVICE1", "SERVICE2", "SERVICE3", "SERVICE4", "SERVICE5",
        "SERVICE6", "SERVICE7", "SERVICE8", "SERVICE9", "SERVICE10",
        "SERVICE11", "SERVICE12", "SERVICE13", "SERVICE14", "SERVICE15",
        "SERVICE16", "SERVICE17", "SERVICE18", "SERVICE19", "SERVICE20",
        "SERVICE21", "SERVICE22", "SERVICE23", "SERVICE24", "SERVICE25",
        "SERVICE26", "SERVICE27", "SERVICE28", "SERVICE29", "SERVICE30",
        "SERVICE31", "SERVICE32", "SERVICE33", "SERVICE34", "SERVICE35",
        "SERVICE36", "SERVICE37", "SERVICE38", "SERVICE39", "SERVICE40",
        "SERVICE41", "SERVICE42", "SERVICE43", "SERVICE44", "SERVICE45",
        "SERVICE46", "SERVICE47", "SERVICE48", "SERVICE49", "SERVICE50",
        "SERVICE51", "SERVICE52", "SERVICE53", "SERVICE54", "SERVICE55",
        "SERVICE56", "SERVICE57", "SERVICE58", "SERVICE59", "SERVICE60",
        "SERVICE61", "SERVICE62", "SERVICE63";

    for (std::string const input : {
             // valid:
             "CC1",
             "CC2",
             "CC3",
             "CC4",
             "SERVICE1",
             "SERVICE2",
             "SERVICE63",
             // invalid:
             "CC0",
             "CC5",
             "SERVICE0",
             "SERVICE64",
         }) {

        bool valid = parse(begin(input), end(input), service|cc);
        std::cout << std::quoted(input) << " -> "
                  << (valid ? "valid" : "invalid") << "\n";
    }
}

版画

"CC1" -> valid
"CC2" -> valid
"CC3" -> valid
"CC4" -> valid
"SERVICE1" -> valid
"SERVICE2" -> valid
"SERVICE63" -> valid
"CC0" -> invalid
"CC5" -> invalid
"SERVICE0" -> invalid
"SERVICE64" -> invalid

Bonus: the strongtyped idea: http://coliru.stacked-crooked.com/a/2cb07d4da9aad39e

语义动作

简而言之:

qi::rule<It, intmax_t(intmax_t min, intmax_t max)> constrained_num =
    qi::uint_[_pass = (_1 >= _r1 && _1 <= _r2)];

qi::rule<It> cc      = "CC" >> constrained_num(1, 4),
             service = "SERVICE" >> constrained_num(1, 63);

Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <iomanip>
namespace qi = boost::spirit::qi;
using It     = std::string::const_iterator;

int main() {
    using namespace qi::labels;
    qi::rule<It, intmax_t(intmax_t min, intmax_t max)> constrained_num =
        qi::uint_[_pass = (_1 >= _r1 && _1 <= _r2)];

    qi::rule<It> cc      = "CC" >> constrained_num(1, 4),
                 service = "SERVICE" >> constrained_num(1, 63);

    for (std::string const input : {
            // valid:
             "CC1",
             "CC2",
             "CC3",
             "CC4",
             "SERVICE1",
             "SERVICE2",
             "SERVICE63",
             // invalid:
             "CC0",
             "CC5",
             "SERVICE0",
             "SERVICE64",
         }) {

        bool valid = parse(begin(input), end(input), service|cc);
        std::cout << std::quoted(input) << " -> "
                  << (valid ? "valid" : "invalid") << "\n";
    }
}
    

打印同上