自学内容网 自学内容网

C++ 正则库与HTTP请求

正则表达式的概念和语法

用于描述和匹配字符串的工具,通过特定的语法规则,灵活的定义复杂字符串匹配条件

常用语法总结

  • 基本字符匹配

    • a:匹配字符'a'
    • abc:匹配字符串'abc'
  • 元字符(特殊含义的字符)

    • .:匹配任意单个字符(除了换行符)
    • ^:匹配字符串的开始位置
    • $:匹配字符串的结束位置
    • *:匹配前面的元素零次或多次
    • +:匹配前面的元素一次或多次
    • ?:匹配前面的元素零次或一次
    • |:表示逻辑“或”操作
    • \:转义字符,用于匹配特殊字符
  • 字符类(匹配一组字符中的任意一个

    • [abc]:匹配'a'、'b'或'c'
    • [a-z]:匹配所有小写字母
    • [^abc]:匹配除'a'、'b'、'c'之外的任意字符
  • 预定义字符类

    • \d:匹配任何数字,等价于[0-9]
    • \D:匹配任何非数字字符
    • \w:匹配任何字母、数字或下划线,等价于[a-zA-Z0-9_]
    • \W:匹配任何非字母、数字或下划线字符
    • \s:匹配任何空白字符(空格、制表符等)
    • \S:匹配任何非空白字符
  • 重复限定符

    • {n}:匹配前面的元素恰好n次
    • {n,}:匹配前面的元素至少n次
    • {n,m}:匹配前面的元素至少n次,至多m次
  • 分组与捕获(分组和捕获匹配的字符串)

    • (abc):匹配'abc',并捕获该匹配
    • (?:abc):匹配'abc',但不捕获该匹配
  • 断言(匹配位置)

    • (?=...):正向先行断言,要求后面的字符必须匹配
    • (?!...):负向先行断言,要求后面的字符不能匹配
    • (?<=...):正向后行断言,要求前面的字符必须匹配
    • (?<!...):负向后行断言,要求前面的字符不能匹配

 

使用

 创建正则表达式对象

正则匹配(检查是否一致);正则搜索(只要包含即可) 

 

正则替换:通过正则表达式,对字符串中的字符进行更换 

 

提取匹配的子字符串,提取的子字符串都存储在了smatch中 

 

处理异常:使用try_catch捕获异常 

 

测试代码汇总 

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

int main()
{
    // std::regex pattern("abc");
    //正则匹配
    // std::string str = "abcddfd";
    // if(std::regex_match(str,pattern))
    // {
    //     std::cout<<"match fount"<<std::endl;
    // }
    // else 
    // {
    //     std::cout<<"match not found"<<std::endl;
    // }

    // //正则搜索(只要有查询的字符即可)
    // if(std::regex_search(str,pattern))
    // {
    //     std::cout<<"search found"<<std::endl;
    // }
    // else
    // {
    //     std::cout<<"search not fount"<<std::endl;
    // }

    // //正则替换
    // std::string replaced = std::regex_replace(str,pattern,"mmm");
    // std::cout<<replaced<<std::endl;

    //提取匹配的子字符串
    std::string str1 = "abc123";
    std::regex pattern("(abc)(\\d+)");
    std::smatch matches;
    if(std::regex_search(str1,matches,pattern))
    {
        for(size_t i =0;i<matches.size();i++)
        {
            std::cout << "Match " << i << ": " << matches[i].str() << std::endl;
        }
    }

    return 0;
}

HTTP解析和响应 

解析请求分析

 

([A-Z]+)

  • [A-Z]:匹配单个大写字母。
  • +:匹配前面的字符一次或多次,即匹配一个或多个大写字母。
  • ():捕获组,用于提取匹配的子字符串。
  • 这个部分匹配HTTP方法,如 GETPOSTPUT 等。

(.+)

  • .:匹配任意单个字符(除换行符外)。
  • +:匹配前面的字符一次或多次,即匹配一个或多个任意字符。
  • ():捕获组,用于提取匹配的子字符串。
  • 这个部分匹配请求的路径,如 /index.html

HTTP/([0-9\\.]+)

  • HTTP/:匹配字符串 HTTP/
  • [0-9\\.]:匹配数字(0-9)或点号(.)。
  • +:匹配前面的字符一次或多次,即匹配一个或多个数字或点号。
  • ():捕获组,用于提取匹配的子字符串。
  • 这个部分匹配HTTP版本号,如 1.1

\r\n

  • \r:匹配回车符。
  • \n:匹配换行符。
  • 这个部分匹配HTTP请求行的结尾。

 解析头部字段

([A-Za-z-]+)

  • [A-Za-z-]:匹配单个字母(大小写皆可)或连字符。
  • +:匹配前面的字符一次或多次,即匹配一个或多个字母或连字符。
  • ():捕获组,用于提取匹配的子字符串。
  • 这个部分匹配头部字段的名称,如 HostUser-AgentAccept

  • 匹配冒号和一个空格,作为头部字段名称与值的分隔符。

(.+)

  • .:匹配任意单个字符(除换行符外)。
  • +:匹配前面的字符一次或多次,即匹配一个或多个任意字符。
  • ():捕获组,用于提取匹配的子字符串。
  • 这个部分匹配头部字段的值,如 www.example.comcurl/7.68.0*/* 等。

/r/n

  • \r:匹配回车符。
  • \n:匹配换行符。
  • 这个部分匹配头部字段行的结尾

 

构成响应

  • 构建状态行:HTTP版本+状态码+状态描述符
  • 构建头部字段:遍历headers哈希表,将其加入到响应字符串职工
  • 构建响应体:头部字段后添加一个空行\r\n,然后追加响应体内容 

 

完整测试代码

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

struct HttpRequest {
    std::string method;
    std::string path;
    std::string version;
    std::map<std::string, std::string> headers;
    std::string body;
};

HttpRequest parseHttpRequest(const std::string& request) {
    HttpRequest httpRequest;
    std::regex requestLinePattern("([A-Z]+) (.+) HTTP/([0-9\\.]+)\r\n");
    std::regex headerPattern("([A-Za-z-]+): (.+)\r\n");

    std::smatch matches;

    // 解析请求行
    if (std::regex_search(request, matches, requestLinePattern)) {
        httpRequest.method = matches[1].str();
        httpRequest.path = matches[2].str();
        httpRequest.version = matches[3].str();
    }

    // 解析头部字段
    auto headersBegin = std::sregex_iterator(request.begin(), request.end(), headerPattern);
    auto headersEnd = std::sregex_iterator();

    for (std::sregex_iterator i = headersBegin; i != headersEnd; ++i) {
        std::smatch match = *i;
        httpRequest.headers[match[1].str()] = match[2].str();
    }

    // 查找请求体的开始位置
    size_t bodyPos = request.find("\r\n\r\n");
    if (bodyPos != std::string::npos) {
        httpRequest.body = request.substr(bodyPos + 4);
    }

    return httpRequest;
}

std::string generateHttpResponse(const std::string& status, const std::map<std::string, std::string>& headers, const std::string& body) {
    std::string response = "HTTP/1.1 " + status + "\r\n";
    
    for (const auto& header : headers) {
        response += header.first + ": " + header.second + "\r\n";
    }
    
    response += "\r\n" + body;
    return response;
}

int main() {
    std::string request = "GET /index.html HTTP/1.1\r\nHost: www.example.com\r\nUser-Agent: curl/7.68.0\r\nAccept: */*\r\n\r\n";
    
    // 解析HTTP请求
    HttpRequest httpRequest = parseHttpRequest(request);
    
    // 打印解析结果
    std::cout << "Method: " << httpRequest.method << std::endl;
    std::cout << "Path: " << httpRequest.path << std::endl;
    std::cout << "Version: " << httpRequest.version << std::endl;
    for (const auto& header : httpRequest.headers) {
        std::cout << header.first << ": " << header.second << std::endl;
    }
    std::cout << "Body: " << httpRequest.body << std::endl;

    // 生成HTTP响应
    std::map<std::string, std::string> headers = {
        {"Content-Type", "text/html"},
        {"Content-Length", "13"}
    };
    std::string body = "<h1>Hello</h1>";
    std::string response = generateHttpResponse("200 OK", headers, body);
    
    // 打印响应报文
    std::cout << response << std::endl;

    return 0;
}

 


原文地址:https://blog.csdn.net/gma999/article/details/140619054

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!