【项目日记(二)】

1、正则库的简单使用

正则表达式:描述了⼀种字符串匹配的模式,可以⽤来检查⼀个串是否含有某种⼦串、将匹配的⼦串替换或者从某个串中取出符合某个条件的⼦串等。 (其实就是字符串匹配规则)
正则库就是提供接口给我们让我们能够使用
应用:正则表达式的使⽤,可以使得HTTP请求的解析更加简单(这⾥指的时程序员的⼯作变得的简单,这并 不代表处理效率会变⾼,实际上效率上是低于直接的字符串处理的),使我们实现的HTTP组件库使⽤起来更加灵活。

bool std::regex_match (const  std::string &src, std::smatches, std::regex &e)

src:原始字符串

matches:正则表达式可以从原始字符串中匹配并提取符合某种规则的数据,提取的数据就放在matches中,是一个类似于数组的容器

e:正则表达式的匹配规则

返回值:用于确定匹配是否成功

正则表达式的简单使用:

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

int main()
{
    std::string str = "/numbers/1234";//提取字符串中的数字字符串
    //---匹配以/numbers/起始,后面跟一个或多个数字字符的字符串,并且在匹配的过程中提取这个匹配到的数字字符串
    std::regex e("/numbers/(\\d+)");//匹配规则
    //  /numbers/  是一个普通字符串字面量,表示要匹配的字符串中必须包含这个字串,且字符顺序号大小都要完全一致
    //  (\\d+)    是一个捕获组  \d  表示匹配一个数字字符(0-9)
    //      + 是一个量词,表示前面的元素(这里是 \d,即数字字符)要出现一次或多次
    //在 \d 前面的反斜杠 \ 需要转义,因为在 C++ 字符串字面量中,反斜杠本身也有转义字符的作用,所以要写成 \\ 才能表示正则表达式中的一个反斜杠。
    //---作用---
    //匹配形如 /numbers/ 后面跟着一个或多个数字的字符串,
    //并且将后面的数字部分作为一个捕获组提取出来,方便后续对其进行处理。
    std::smatch matches;
    bool ret = std::regex_match(str, matches, e);
    if(ret == false)
    {
        return -1;
    }
    //肯定首先存储到的是原始字符串 然后再存数组字符串
    for(auto &s :matches)
    {
        std::cout << s << std::endl;
    }
    return 0;
}

HTTP请求行中请求方法的匹配:

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

int main()
{
    //HTTP请求行格式: 请求方法 GET /baidu/login?user=xiaoming&pass=123123 HTTP/1.1\r\n
    std::string str = "GET /baidu/login?user=xiaoming&pass=123123 HTTP/1.1\r\n";
    std::smatch matches;
    //1、请求方法的匹配 GET HEAD POST PUT DELETE
    //2、资源路径的提取 GET之后空格 到?之前结束
    //3、查询字符串提取 ?之后空格之前的
    //4、HTTP协议版本提取
    std::regex e("(GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\n|\r\n)?");
    //注意: (空格)表示匹配空格,上一个正则表达式会匹配到下一个正则表达式的内容之前停止匹配
    //括号表示要提取的数据
    //[^?] 表示匹配非?字符
    //\\?表示原始? (.*) 表示提取?之后的任意字符0次或多次 ,直到遇到空格
    //(HTTP/1\\.[01])  表示以HTTP/1.开始  \\. 表示原始的. 字符 [01]表示匹配0或1 其中的一个
    //.是匹配任意非\n\r的字符  *匹配0次或多次
    //(?:\n|\r\n)?  (?: ...) 表示匹配某个格式字符串 但是不提取 最后的? 表示匹配前边的表达式0次或1次

    //如果请求格式里面没有 查询字符串将 \\?(.*)写为(?:\\?(.*))?   ---即可以有 也可以没有

    bool ret = std::regex_match(str, matches, e);
    if(ret = false)
    {
        return -1;
    }
    for(auto &s : matches)
    {
        std::cout << s << std::endl;
    }
    return 0;
}

2、通用类型any类型的实现

我们的这个高并发服务器是可以支持各种不同的协议,我们进行协议支持的时候,socket有数据到来了,我们去接收数据的时候,缓冲区中的数据不足一条完整的请求,或者比一条完整的请求多。我们就得考虑将socket缓冲区中的数据进行处理,那么数据处理到一半的时候,就得考虑在下次数据到来的时候继续处理,因此,我们就需要给服务器中的每一个连接都设置一个协议处理的上下文,专门用来控制请求数据接收和处理的节奏的。(接收到的数据和解析)

我们的服务器不单单要支持http协议,还要支持其他不同的协议,所以就不能是一个固定格式的上下文,因此我们就要有容器去接收不同结构的数据

1、一个连接必须拥有一个请求接收与解析的上下文

2、上下文的类型不能固定,因为服务器支持的协议可能会不断增多,不同的协议,可能会有不同的上下文结构

结论:必须拥有一个容器,能够保存各种不同的类型结构数据

设计实现一个any类:

1、是一个容器,容器中可以保存不同类型的数据

解决方案:

a、模板:

        template<class T>
        class Any{

        private:

                T _content;

        }

实例化对象的时候,必须指定容器保存的数据类型: Any <int> a;

而我们需要的是: Any a; a = 10; a = "abc..."  可以接收不同类型的数据

因此,模板是搞不定的。

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

       

class Any //Any类实现一个通用的类型容器,可以存储任意类型的值
{
private:
    class holder//私有内部类 为存储不同类型值的具体实现提供一个公共抽象接口或基类结构
    {
        //....
    };
    template <class T>//可以根据不同的类型T实例化不同的 placeholer 类
    class placeholer : public holder//表示 placeholer 类是从 holder 类派生而来的
    //这是实现多态的一种方式,使得 placeholer 类可以作为 holder 类的一种具体实现
    {
        T _val;
    };

    holder *_content;//声明了一个 Any 类的私有成员变量 _content
    //它是一个指向 holder 类的指针
    //这个指针的作用是用于存储实际的类型值的对象
    //通过这个指针,Any 类可以在运行时根据存储的值的实际类型来操作和管理这些值,
    //实现了存储任意类型值的功能
    //holder指针_content可以指向不同类型的placeholer对象,这为实现多态奠定了基础
    //多态允许在运行时根据对象的实际类型调用相应的方法
};

placeholer类继承自holder类,通过继承可以实现多态,让Any类可以使用holder指针来管理不同类型的placeholer对象。

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

简单代码实现:

#include <iostream>
#include <typeinfo>
#include <cassert>

class Any
{
private:
    class holder //基类
    {
    public:
        virtual ~holder();
        //设置为纯虚函数,是为了让派生类实现该函数,从而实现多态
        virtual const std::type_info& type() = 0;
        virtual holder *clone() = 0;
    };

    template<class T>
    class placeholder: public holder  //派生类
    {
    public:
        placeholder(const T &val) :_val(val){}

        virtual const std::type_info& type() //获取子类对象保存的数据类型
        {
            return typeid(T);//通过 typeid(T) 能获取 T 的类型信息,并且返回其常量引用,这样就能在运行时得知 Any 容器里存储的数据类型
        }
        virtual holder *clone()//针对当前的对象自身克隆出一个新的子类对象
        {
            return new placeholder(_val); //创建新的placeholder对象,这个对象存储数据和当前对象相同  最后返回指向新对象的holder指针
        }
    public:
        T _val;
    };
    holder *_content;///holder类型的指针(基类类型的指针) 是Any类的私有成员变量
    //用于存储实际的placeholder对象 从而实现存储任意类型数据的功能
public:
    默认构造函数
    Any():_content(NULL){} 

    //类模板构造函数
    template<class T>
    Any(const T &val) //直接给数据构造通用容器
    :_content(new placeholder<T>(val)) //将val存储在Any容器中
    {}

    //类的拷贝构造函数   //通过其他的容器构造新的容器
    Any(const Any &other) //
    :_content(other._content ? other._content->clone() : NULL)
    //如果other._content不为空,就调用clone()克隆other对象  并将新对象的指针赋给_content 否则将 _content 赋值为 NULL
    {}

    ~Any()
    {delete _content;}

    Any &swap(Any &other)
    {
        std::swap(_content, other._content);
        return *this; //返回当前对象的引用
    }

    template<class T>
    T *get() //获取保存对象的类型 可以是任意类型 返回子类对象保存的数据的指针
    {
        //想要获取的数据类型,必须和保存的数据类型一致
        assert(typeid(T) == _content->type());
        return &((placeholder<T>*)_content)->_val; //将 _content 指针转换为 placeholder<T>* 类型,然后返回存储数据 _val 的地址
    }
    //各种通用容器给容器赋值重载=运算符
    template<class T>
    Any& operator=(const T &val)
    {
        //为val构造一个临时通用容器,然后与当前容器自身进行指针交换,临时对象释放的时候,原先保存的数据也就被释放了
        Any(val).swap(*this);
        return *this;
    }
    Any& operator=(const Any &other)
    {
        Any(other).swap(*this);
        return *this;
    }
};

class Test
{
public:
    Test() { std::cout<<"构造" << std::endl;}
    Test(const Test &t) { std::cout << "拷贝" << std::endl;}
    ~Test() { std::cout<<"析构" << std::endl;}
};

int main()
{

    //std::any a;
    //a = 10;
    //int *pi = std::any_cast<int>(&a);
    //std::cout << *pi << std::endl;

    //a = std::string("hello");
    //std::string *ps = std::any_cast<std::string>(&a);
    //std::cout << *ps << std::endl;

    Any a;
    {
        Test t;
        a = t;
    }
    a = 10;
    int *pa = a.get<int>();
    std::cout << *pa << std::endl;
    a = std::string("nihao");
    std::string *ps = a.get<std::string>();
    std::cout << *ps << std::endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值