云计算百科
云计算领域专业知识百科平台

仿muduo库的高并发服务器——正则表达式与any类介绍及其简单模拟实现

        本期我们接着深入项目的编写。

        相关代码已经上传至作者个人gitee:仿muduo服务器: 本项目致力于实现一个仿造muduo库的简易并发服务器,为个人项目,参考即可喜欢请点个赞谢谢

目录

正则表达式

       

库的接口介绍

        正则表达式解析处理HTTP请求

any类

       

类介绍

        默认构造与值构造 / 赋值

 std::make_any

(args…)

 has_value()

  type()

 std::any_cast

 emplace

(args…)

 reset()

  swap()

        设计思想


正则表达式

        正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。         正则表达式的使用,可以使得HTTP请求的解析更加简单(这里指的是程序员的工作变得简单,这并不代表处理效率会变高,实际上效率上是低于直接的字符串处理的),使我们实现的HTTP组件库使用起来更加灵活。

        在C++中,<regex>就是为了正则表达式实现的库

        <regex>库的接口介绍

  • std::regex

    • 表达式:std::regex r(const std::string& pattern, flag_type flags = ECMAScript);

    • 参数:pattern 为正则表达式字符串;flags 可选语法选项(如 ECMAScript、basic、extended、icase 等)。

    • 作用:编译正则表达式,存储为一个可用的正则对象。

  • std::regex_match

    • 表达式:bool regex_match(const std::string& s, std::smatch& m, const std::regex& r);

    • 参数:s 为源字符串;m 用于存储匹配结果(子匹配组);r 为已编译的正则对象。

    • 作用:检查整个字符串是否完全匹配正则表达式(从开头到结尾必须完全符合)。

  • std::regex_search

    • 表达式:bool regex_search(const std::string& s, std::smatch& m, const std::regex& r);

    • 参数:同上,m 存储首次匹配的子串及捕获组。

    • 作用:在字符串中搜索第一个匹配正则表达式的子序列(不需要全串匹配)。

  • std::regex_replace

    • 表达式:std::string regex_replace(const std::string& s, const std::regex& r, const std::string& fmt);

    • 参数:s 源字符串;r 正则对象;fmt 替换格式字符串(可用 $1、$2 引用捕获组)。

    • 作用:查找所有匹配正则的子串,并用 fmt 替换,返回新字符串。

  • std::sregex_iterator

    • 表达式:std::sregex_iterator it(s.begin(), s.end(), r);

    • 参数:迭代器范围(字符串首尾)和正则对象。

    • 作用:迭代遍历字符串中所有匹配的子串,每次解引用得到 std::smatch 对象,用于批量处理匹配。

  •         示例:

    #include <iostream>
    #include <regex>
    #include <string>

    int main()
    {
    std::string text = "Contact: alice@example.com, bob@test.org";
    std::regex email_pattern(R"([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})");

    // 1. regex_match:要求整个字符串完全匹配
    std::string single = "user@domain.com";
    if (std::regex_match(single, email_pattern))
    std::cout << "Full match: " << single << " is an email\\n";
    else
    std::cout << "Not a full match\\n";

    // 2. regex_search:查找第一个匹配的子串
    std::smatch match;
    if (std::regex_search(text, match, email_pattern))
    std::cout << "First email found: " << match[0] << "\\n";

    // 3. regex_replace:替换所有匹配项
    std::string replaced = std::regex_replace(text, email_pattern, "[EMAIL]");
    std::cout << "Replaced text: " << replaced << "\\n";

    // 4. sregex_iterator:遍历所有匹配项
    std::cout << "All emails: ";
    for (std::sregex_iterator it(text.begin(), text.end(), email_pattern), end; it != end; ++it)
    std::cout << it->str() << " ";
    std::cout << "\\n";

    return 0;
    }

            结果为:

            正则表达式解析处理HTTP请求

    #include <iostream>
    #include <regex>
    #include <string>

    int main()
    {
    // 示例 HTTP 请求行
    std::string request_line = "GET /api/users?id=123&name=john HTTP/1.1";

    // 正则表达式:
    // 分组1: 方法 (大写字母)
    // 分组2: 路径 (非空白且不含 '?')
    // 分组3: 查询字符串 (可选,'?' 后非空白字符)
    // 分组4: HTTP版本 (HTTP/x.x)
    std::regex pattern(R"(^([A-Z]+)\\s+([^\\s?]+)(?:\\?([^\\s]+))?\\s+(HTTP/\\d\\.\\d)$)");

    std::smatch matches;
    if (std::regex_match(request_line, matches, pattern)) {
    std::cout << "完整请求行: " << request_line << "\\n\\n";
    std::cout << "请求方法: " << matches[1] << std::endl;
    std::cout << "请求路径: " << matches[2] << std::endl;

    // 查询字符串可能不存在
    if (matches[3].matched)
    std::cout << "查询字符串: " << matches[3] << std::endl;
    else
    std::cout << "查询字符串: (无)" << std::endl;

    std::cout << "HTTP版本: " << matches[4] << std::endl;
    } else {
    std::cerr << "请求行格式不匹配" << std::endl;
    }

    return 0;
    }

    结果为:

    any类

            每一个Connection对连接进行管理,最终都不可避免需要涉及到应用层协议的处理,因此在Connection中需要设置协议处理的上下文来控制处理节奏。但是应用层协议千千万,为了降低耦合度,这个协议接收解析上下文就不能有明显的协议倾向,它可以是任意协议的上下文信息,因此就需要一个通用的类型来保存各种不同的数据结构。         在C语言中,通用类型可以使用void*来管理,但是在C++中,boost库和C++17给我们提供了一个通用类型any来灵活使用,如果考虑增加代码的移植性,尽量减少第三方库的依赖,则可以使用C++17特性中的any,或者自己来实现。

            <any>类介绍

            默认构造与值构造 / 赋值

    表达式: std::any a; 或 std::any a = 值; 参数: 无参构造得到空对象;若传入任意可拷贝类型 T 的值,则从该值构造或赋值。 作用: 创建一个 std::any 容器。默认构造时不含任何值(has_value() 返回 false)。传入具体值时,内部会存储一份 T 的拷贝(或通过移动语义接管资源),此后该 any 对象便拥有该类型的有效数据。

     std::make_any<T>(args…)

    表达式: auto a = std::make_any<T>(构造参数…); 参数: 目标类型 T 及其构造函数所需的实参列表。 作用: 直接在 any 内部原地构造 T 类型的对象,完全避免临时对象的产生与多余的拷贝/移动开销。与先构造临时对象再存入 any 相比,它更高效且异常安全。

     has_value()

    表达式: a.has_value() 参数: 无。 作用: 返回布尔值,指示当前 any 对象是否持有有效值(即非空)。空 any 通常由默认构造、调用 reset() 或被移走值产生。

      type()

    表达式: a.type() 参数: 无。 作用: 返回 const std::type_info&,代表当前所存储对象的准确类型。若 any 为空,则返回 typeid(void)。该接口是进行类型安全检查的基础,常与 any_cast 的指针形式配合使用。

     std::any_cast<T>

    表达式: 存在两种重载形式:

    • 引用形式:std::any_cast<T>(a)

    • 指针形式:std::any_cast<T>(&a) 参数: 前者接受 any 对象的引用;后者接受 any 对象的指针。 作用: 提取 any 中存储的值。

    • 引用形式:若存储类型与 T 不匹配,抛出 std::bad_any_cast 异常。

    • 指针形式:若存储类型与 T 不匹配,返回 nullptr;匹配则返回指向内部存储对象的指针。推荐优先使用指针形式进行安全访问。

     emplace<T>(args…)

    表达式: a.emplace<T>(构造参数…); 参数: 目标类型 T 及其构造参数。 作用: 销毁当前存储的任何旧值(如果有),然后在原地构造一个新的 T 类型对象。它避免了先构造临时值再赋值的中间步骤,且能复用已分配的内存(如果实现支持),提高运行期变更类型时的效率。

     reset()

    表达式: a.reset(); 参数: 无。 作用: 销毁当前存储的对象(调用其析构函数),并将 any 对象重置为空状态。调用后 has_value() 将返回 false。该操作不会影响 any 对象本身的存储空间,仅是清空其内容。

      swap()

    表达式: a1.swap(a2); 或 std::swap(a1, a2); 参数: 另一个同类型的 std::any 对象。 作用: 交换两个 any 容器所持有的值以及它们的状态。该操作是高效的,通常仅交换内部指针或控制块,不涉及所存储类型的拷贝或移动构造。

            示例代码

    #include <any>
    #include <iostream>
    #include <string>
    #include <vector>

    int main()
    {
    // 1. 默认构造(空 any)
    std::any a;
    std::cout << "1. 默认构造后 has_value(): " << a.has_value() << '\\n';

    // 2. 值构造:存入 int
    std::any b = 42; // 隐式转换自 int
    std::any c(std::string("hello")); // 显式构造
    std::cout << "2. 存入 int: " << std::any_cast<int>(b) << '\\n';

    // 3. std::make_any:原地构造 vector,避免临时对象
    auto d = std::make_any<std::vector<int>>(3, 10); // 三个 10
    std::cout << "3. make_any<vector>: size="
    << std::any_cast<std::vector<int>>(d).size() << '\\n';

    // 4. has_value() 和 type()
    std::cout << "4. d 是否含有值? " << d.has_value()
    << ", 类型名: " << d.type().name() << '\\n';

    // 5. any_cast 指针形式(安全访问)
    if (auto* ptr = std::any_cast<std::string>(&c))
    {
    std::cout << "5. 指针提取 string: " << *ptr << '\\n';
    }
    if (auto* ptr = std::any_cast<int>(&c))
    {
    // 不会执行,因为 c 里是 string
    }
    else
    {
    std::cout << " 类型不匹配,返回 nullptr\\n";
    }

    // 6. any_cast 引用形式(可能抛异常)
    try
    {
    std::cout << "6. 引用提取 int: " << std::any_cast<int>(b) << '\\n';
    // 下面这行将抛出 std::bad_any_cast
    // std::cout << std::any_cast<double>(b);
    }
    catch (const std::bad_any_cast& e)
    {
    std::cout << " 捕获异常: " << e.what() << '\\n';
    }

    // 7. emplace:销毁旧值,原地构造新类型
    b.emplace<double>(3.14159);
    std::cout << "7. emplace<double> 后: " << std::any_cast<double>(b) << '\\n';

    // 8. reset:清空内容
    b.reset();
    std::cout << "8. reset 后 has_value(): " << b.has_value() << '\\n';

    // 9. swap:交换两个 any 的内容
    std::any x = 100;
    std::any y = std::string("world");
    std::cout << "9. 交换前: x=" << std::any_cast<int>(x)
    << ", y=" << std::any_cast<std::string>(y) << '\\n';
    x.swap(y);
    std::cout << " 交换后: x=" << std::any_cast<std::string>(x)
    << ", y=" << std::any_cast<int>(y) << '\\n';

    return 0;
    }

    结果为:

            设计思想

            嵌套一下,设计一个类,专门用于保存其他类型的数据,而Any类保存的是固定类的对象

    class Any
    {
    private:
    class holder
    {
    ….
    };
    template<class T>
    class placeholder: holder
    {
    T_val I
    };
    holder *content;
    };

    Any类中,保存的是holder类的指针,当Any容器需要保存一个数据的时候,只需要通过placeholder子类实例化一个特定类型的子类对象出来,让子类对象保存数据

            源代码:

    #pragma once

    #include <utility>
    #include <typeinfo>

    class Any
    {
    private:
    class holder
    {
    public:
    virtual ~holder() {}
    virtual const std::type_info& type() const = 0;
    virtual holder* clone() const = 0;
    };

    template<class T>
    class placeholder : public holder
    {
    public:
    placeholder(const T& val) : _val(val) {}
    virtual ~placeholder() = default;

    virtual const std::type_info& type() const override {
    return typeid(_val);
    }

    virtual holder* clone() const override {
    return new placeholder<T>(_val);
    }

    T _val;
    };

    holder* _holder;

    public:
    Any() : _holder(nullptr) {}

    template<class T>
    Any(const T& val) : _holder(new placeholder<T>(val)) {}

    Any(const Any& other)
    : _holder(other._holder ? other._holder->clone() : nullptr) {}

    ~Any() {
    delete _holder;
    }

    Any& Swap(Any& other) noexcept {
    std::swap(_holder, other._holder);
    return *this;
    }

    // 从任意类型赋值
    template<class T>
    Any& operator=(const T& val) {
    Any(val).Swap(*this);
    return *this;
    }

    // 拷贝赋值运算符(非模板)
    Any& operator=(const Any& other) {
    Any(other).Swap(*this);
    return *this;
    }

    // 获取存储值的指针(非常量版本)
    template<class T>
    T* get() {
    if (_holder && typeid(*_holder) == typeid(placeholder<T>)) {
    return &(static_cast<placeholder<T>*>(_holder)->_val);
    }
    return nullptr;
    }

    // 获取存储值的指针(常量版本)
    template<class T>
    const T* get() const {
    if (_holder && typeid(*_holder) == typeid(placeholder<T>)) {
    return &(static_cast<const placeholder<T>*>(_holder)->_val);
    }
    return nullptr;
    }
    };

            测试

    #include "MyAny.h"
    #include <iostream>
    #include <cassert>
    #include <string>

    class TestCounter
    {
    public:
    static int construct_count;
    static int destruct_count;

    TestCounter() { construct_count++; }
    TestCounter(const TestCounter&) { construct_count++; }
    ~TestCounter() { destruct_count++; }
    };

    int TestCounter::construct_count = 0;
    int TestCounter::destruct_count = 0;

    void test_default_constructor()
    {
    std::cout << "Test 1: Default Constructor" << std::endl;
    Any a;
    assert(a.get<int>() == nullptr);
    std::cout << " PASSED" << std::endl;
    }

    void test_template_constructor()
    {
    std::cout << "Test 2: Template Constructor" << std::endl;

    Any a1(42);
    Any a2(3.14);
    Any a3(std::string("hello"));

    std::cout << " PASSED" << std::endl;
    }

    void test_copy_constructor()
    {
    std::cout << "Test 3: Copy Constructor" << std::endl;

    Any a1(42);
    Any a2(a1);

    Any a3(std::string("test"));
    Any a4(a3);

    std::cout << " PASSED" << std::endl;
    }

    void test_destructor()
    {
    std::cout << "Test 4: Destructor" << std::endl;

    TestCounter::construct_count = 0;
    TestCounter::destruct_count = 0;

    {
    Any a{TestCounter()}; // 修复 most vexing parse
    }

    assert(TestCounter::construct_count == TestCounter::destruct_count);
    std::cout << " PASSED" << std::endl;
    }

    void test_swap()
    {
    std::cout << "Test 5: Swap Method" << std::endl;

    Any a1(42);
    Any a2(3.14);

    a1.Swap(a2);

    std::cout << " PASSED" << std::endl;
    }

    void test_get()
    {
    std::cout << "Test 6: Get Method" << std::endl;

    Any a1(42);
    Any a2(3.14);
    Any a3(std::string("hello"));

    int* p1 = a1.get<int>();
    double* p2 = a2.get<double>();
    std::string* p3 = a3.get<std::string>();

    if (p1)
    {
    std::cout << " int value: " << *p1 << std::endl;
    }
    if (p2) {
    std::cout << " double value: " << *p2 << std::endl;
    }
    if (p3) {
    std::cout << " string value: " << *p3 << std::endl;
    }

    double* wrong_type = a1.get<double>(); // 修改这里
    assert(wrong_type == nullptr);

    std::cout << " PASSED" << std::endl;
    }

    void test_assignment_operator_value()
    {
    std::cout << "Test 7: Assignment Operator (Value)" << std::endl;

    Any a1;
    a1 = 42;

    Any a2;
    a2 = 3.14;

    Any a3;
    a3 = std::string("test");

    std::cout << " PASSED" << std::endl;
    }

    void test_assignment_operator_any()
    {
    std::cout << "Test 8: Assignment Operator (Any)" << std::endl;

    Any a1(42);
    Any a2;
    a2 = a1;

    Any a3(std::string("hello"));
    Any a4;
    a4 = a3;

    std::cout << " PASSED" << std::endl;
    }

    void test_self_assignment()
    {
    std::cout << "Test 9: Self Assignment" << std::endl;

    Any a(42);
    a = a;

    std::cout << " PASSED" << std::endl;
    }

    void test_chained_assignment()
    {
    std::cout << "Test 10: Chained Assignment" << std::endl;

    Any a1(42);
    Any a2;
    Any a3;

    a3 = a2 = a1;

    std::cout << " PASSED" << std::endl;
    }

    void test_multiple_types()
    {
    std::cout << "Test 11: Multiple Types" << std::endl;

    Any a1(42);
    Any a2(3.14);
    Any a3('c');
    Any a4(true);
    Any a5(std::string("hello"));

    std::cout << " PASSED" << std::endl;
    }

    void test_empty_any()
    {
    std::cout << "Test 12: Empty Any Operations" << std::endl;

    Any a1;
    Any a2;

    a1.Swap(a2);

    Any a3;
    a3 = a1;

    std::cout << " PASSED" << std::endl;
    }

    void test_overwrite_value()
    {
    std::cout << "Test 13: Overwrite Value" << std::endl;

    Any a(42);
    a = 3.14;

    std::cout << " PASSED" << std::endl;
    }

    void test_complex_type()
    {
    std::cout << "Test 14: Complex Type" << std::endl;

    struct Point {
    int x, y;
    Point(int x_, int y_) : x(x_), y(y_) {}
    };

    Any a(Point(10, 20));
    Point* p = a.get<Point>();

    if (p) {
    std::cout << " Point: (" << p->x << ", " << p->y << ")" << std::endl;
    }

    std::cout << " PASSED" << std::endl;
    }

    void test_swap_with_empty()
    {
    std::cout << "Test 15: Swap with Empty Any" << std::endl;

    Any a1(42);
    Any a2;

    a1.Swap(a2);

    std::cout << " PASSED" << std::endl;
    }

    int main()
    {
    std::cout << "=== MyAny Unit Tests ===" << std::endl << std::endl;

    test_default_constructor();
    test_template_constructor();
    test_copy_constructor();
    test_destructor();
    test_swap();
    test_get();
    test_assignment_operator_value();
    test_assignment_operator_any();
    test_self_assignment();
    test_chained_assignment();
    test_multiple_types();
    test_empty_any();
    test_overwrite_value();
    test_complex_type();
    test_swap_with_empty();

    std::cout << std::endl << "=== All Tests Completed ===" << std::endl;
    return 0;
    }

            结果为:

            本期内容就到这里了,喜欢请点个赞谢谢

    封面图自取:

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 仿muduo库的高并发服务器——正则表达式与any类介绍及其简单模拟实现
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!