• 1.X3-Warming up


    /*
    此程序使用 Boost Spirit 库来解析用户提供的逗号分隔的数字列表。它演示了如何使用 Spirit 来定义解析
    器和执行解析操作,并且在用户输入时反复执行解析操作。用户可以提供一系列逗号分隔的数字,程序会检查它们
    是否符合指定的解析规则。如果解析成功,程序将输出解析成功的消息,否则将输出解析失败的消息。
    */
    #include 
    
    #include 
    #include 
    #include 
    
    namespace client	//创建了名为 "client" 的命名空间,用于组织程序的代码。
    {
        namespace x3 = boost::spirit::x3;  //创建了别名
        namespace ascii = boost::spirit::x3::ascii;
    
        ///
        //  Our number list parser
        ///
        template <typename Iterator>
        bool parse_numbers(Iterator first, Iterator last)
        {
            using x3::double_;			//引入了 Spirit 的 double_ 解析器,用于解析浮点数
            using x3::phrase_parse;     //引入了 Spirit 的 phrase_parse 函数,用于执行解析。
            using ascii::space;			//:引入了 Spirit 的 space 解析器,用于跳过空白字符。
    
            bool r = phrase_parse(
                first,                          // Start Iterator
                last,                           // End Iterator
                double_ >> *(',' >> double_),   // The Parser
                space                           // The Skip-Parser
            );
            if (first != last) // fail if we did not get a full match
                return false;
            return r;
        }
    }
    
    
    //  Main program
    
    int
    main()
    {
        std::cout << "/\n\n";
        std::cout << "\t\tA comma separated list parser for Spirit...\n\n";
        std::cout << "/\n\n";
    
        std::cout << "Give me a comma separated list of numbers.\n";
        std::cout << "Type [q or Q] to quit\n\n";
    
        std::string str;
        while (getline(std::cin, str))
        {
            if (str.empty() || str[0] == 'q' || str[0] == 'Q')
                break;
    
            if (client::parse_numbers(str.begin(), str.end()))
            {
                std::cout << "-------------------------\n";
                std::cout << "Parsing succeeded\n";
                std::cout << str << " Parses OK: " << std::endl;
            }
            else
            {
                std::cout << "-------------------------\n";
                std::cout << "Parsing failed\n";
                std::cout << "-------------------------\n";
            }
        }
    
        std::cout << "Bye... :-) \n\n";
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    Trivial Example #1 Parsing a number

    创建一个解析器,用于解析浮点数。

    double_
    
    • 1

    Trivial Example #2 Parsing two numbers

    创建一个解析器,用于接受包含两个浮点数的一行。

    double_ >> double_
    
    • 1

    这段代码创建了一个解析器,可以识别包含两个浮点数的文本行。解析时,这两个浮点数需要通过逗号或空格等分隔符分开。程序中使用 double_ >> double_ 表达式,它将两个 double_ 解析器连接在一起,表示需要解析两个浮点数,它们之间用 “>>” 操作符表示“后跟”。这个示例强调了如何将简单的解析器组合成更复杂的解析器,以便解析更复杂的文本结构。

    Trivial Example #3 Parsing zero or more numbers

    创建一个解析器,可以接受零个或多个浮点数。

    *double_
    
    • 1

    这段代码创建了一个解析器,可以接受零个或多个浮点数。它使用了 *double_,其中 * 是Kleene星号,表示可以重复出现前面的 double_ 解析器来匹配零个或多个浮点数。这是一种灵活的解析方式,允许匹配任意数量的浮点数,它类似于正则表达式中的 “*”,用于表示重复出现。作者提到了C++程序员可能会感到不太熟悉这种运算符的重载方式,但这是因为必须遵守C++的语法规则。

    Trivial Example #4 Parsing a comma-delimited list of numbers

    这个示例将创建一个解析器,用于接受逗号分隔的数字列表。

    double_ >> *(char_(',') >> double_)
    
    • 1

    注意 char_(‘,’)。它是一个字符字面值解析器,可以识别逗号 ‘,’。在这种情况下,Kleene星号修改了一个更复杂的解析器,即由以下表达式生成的解析器:

    (char_(',') >> double_)
    
    • 1

    这段代码创建了一个解析器,用于解析逗号分隔的数字列表。解析过程中,它期望一个浮点数,后面可以跟随零个或多个由逗号分隔的其他浮点数。double_ >> *(char_(',') >> double_) 表达式中,double_ 解析一个浮点数,*(char_(',') >> double_) 则表示零个或多个由逗号分隔的浮点数。char_(',') 用于识别逗号字符。括号用来确保逗号字符和浮点数之间的关系被正确解析。这个解析器的设计允许它有效地处理逗号分隔的数字列表。

    Let’s Parse!

    我们已经完成了解析器的定义。下一步是调用这个解析器来执行它的工作。有几种方法可以实现这一点。现在,我们将使用 phrase_parse 函数。这个函数的一个重载接受四个参数:

    1. 指向输入的起始位置的迭代器。
    2. 指向输入的结束位置之后的迭代器。
    3. 解析器对象。
    4. 另一个名为跳过解析器(skip parser)的解析器。
      在我们的示例中,我们希望跳过空格和制表符。Spirit库中还包括了另一个名为 space 的预定义解析器,它是一个非常简单的解析器,只识别空白字符。我们将使用 space 作为我们的跳过解析器。跳过解析器负责在解析器元素之间跳过字符,例如 double_ 和 char_。

    好的,现在让我们开始解析!

    template <typename Iterator>
    bool parse_numbers(Iterator first, Iterator last)
    {
        using x3::double_;
        using x3::phrase_parse;
        using ascii::space;
    
        bool r = phrase_parse(
            first,                          //  Start Iterator
            last,                           //  End Iterator
            double_ >> *(',' >> double_),   //  The Parser
            space                           //  The Skip-Parser
        );
        if (first != last) // fail if we did not get a full match
            return false;
        return r;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    parse 函数返回 truefalse 取决于解析的结果。第一个迭代器以引用的方式传递。在成功解析时,这个迭代器会被重新定位到被解析器消耗的最右侧位置。如果这个位置等于 last,那么就有了完全匹配。如果不等于 last,那么就有了部分匹配。部分匹配发生在解析器只能解析输入的一部分时。

    需要注意的是,我们在调用 parse 时直接将解析器嵌入到调用中。调用 parse 时,表达式会评估为一个临时的无名解析器,然后传递给 parse() 函数,被使用,然后销毁。

    在这里,我们选择使解析器通用化,通过将其作为一个模板来实现,参数化迭代器类型。通过这种方式,它可以接受来自任何符合STL标准的序列的数据,只要迭代器符合前向迭代器的要求。

  • 相关阅读:
    Label 相关论文汇总
    基于Socket编程Java和mysql实现的简易微信设计
    11.30 - 每日一题 - 408
    【FreeRTOS(十三)】任务通知
    【图像检测】基于计算机视觉实现手位置检测附matlab代码
    【AI算法岗面试八股面经【超全整理】——机器学习】
    恒峰|高压森林应急消防泵|守护森林安全
    archery集成ldap无法登陆
    【力扣周赛】第 364 场周赛⭐(前后缀分解+单调栈&DFS技巧)
    南美哥伦比亚市场最全分析开发攻略,收藏一篇就够了
  • 原文地址:https://blog.csdn.net/qq_40178082/article/details/133839989