c++分割std::string成多个string

问题描述

假设我们有一个http服务器,此服务器接收客户端发来的http请求,假设请求如下

GET / HTTP/1.1

我们怎么将这个Http请求分割成三份,分别存入不同的string中分别处理?

前置知识

首先std::string的本身存于stack中,但是std::string指向的string存于Heap中,std::string在stack作用域消失的时候自动清除Heap中的字符串

关于std::string的操作
假设我们有一个std::string如下

std::string s;

我们可以有以下的操作

寻找指定字符

s.find('c');

寻找std::string s中的字符c的位子,且返回其下标

s.find('c', 10);

std::string s的下标10开始寻找字符c,且返回其下标

注意下标是从1开始算,而不是0

我们的find找到最后可能会返回一个不存在的数字,这个数字就是std::string::npos;,我们可以将这个数字当成find的结束符号(如果find在循环中)

s.find('c', POSITION);

如果我们从str::find返回的结果中查找,比如上述代码POSITION就是一个str.find()的返回值,上述代码会从POSITION的位子开始找(包含POSITION)

分割字符串成子字符串

s.substr(start, end);

对于std::string s从index为start开始到index为end结束(不包括end)的字符串截取出来返回

比如我们有一个字符串"hello world"我们对其做s.substr(0, 7);结果是返回"hello w",也就是返回index从0到6的字符串
index是从0开始
假如我们传入的是2个从s.find查找的结果,就从这个位子开始截取,比如我们有字符串"abcdefghij"P1指向'b'(P1s.find的返回值),P2指向'f'(P2也是s.find的返回值),我们截取字符串s.substr(P1, P2);得到的结果等于"bcdef"

解决代码

那么我们就非常容易解决上述问题

#include <iostream>
//#include <thread>
#include <string>
#include <vector>

int main(){

    std::vector<std::string> v;

    std::string s{"GET / HTTP/1.1"};

    std::string::size_type start = 0;
    std::string::size_type end = s.find(' ');
   
    for(int i = 0; i < 3; i++){
        if(end == std::string::npos) v.push_back(s.substr(start, s.length()));
        std::cout << s.substr(start, end-start) << "\n";
        v.push_back(s.substr(start, end-start));
        start = ++end;
        end = s.find(' ', end);
    }
    /*
    for(auto i: v){
        std::cout << i <<'\n';
    } 
    */  
}

根据上述的方法给我们一个url,我们如何将其截取出scheme,host,port,path?
解决方法如下

#include <iostream>
#include <string>
#include <vector>
#include <memory>

class uri{
public:
    uri();
    ~uri() = default;
    
    bool                      parseuri(const std::string&);
    std::string               get_scheme() const ;
    std::string               get_host()   const;
    uint16_t                  get_port()   const;
    std::vector<std::string>  get_path()   const;


private:
    struct Impl;
    std::shared_ptr<struct Impl> impl_;
};

struct uri::Impl{
    std::string scheme;
    std::string host;
    uint16_t port;
    std::vector<std::string> path;
};

uri::uri()
: impl_(new Impl){

}

bool uri::parseuri(const std::string& uri){
    //注意uri.find('X', POSISTION)是从POSISTION这个下标开始find最重要的寻找范围包括这个下标

    auto colon = uri.find(':');
    impl_->scheme = uri.substr(0, colon);

    auto slash = uri.find('/', colon+1);
    auto sec_slash = uri.find('/', slash+1);
    auto path_root = uri.find('/', sec_slash+1);
    
    auto sec_colon = uri.find(':', slash);
    if(sec_colon == std::string::npos){ //没有第二个冒号也意味着没有端口号那么直接默认80
        impl_->port = 80;
        impl_->host = uri.substr(sec_slash+1, path_root-sec_slash-1);
    }else{ //带表有第二个冒号也就是指定了端口号
        impl_->port = std::stoi(uri.substr(sec_colon + 1, path_root - sec_colon - 1));
        impl_->host = uri.substr(sec_slash+1, sec_colon - sec_slash - 1);
    }

    auto start = path_root;
    auto end = start;

    while((end = uri.find('/', end + 1))!= std::string::npos){
        impl_->path.push_back(uri.substr(start + 1, end - start - 1));
        start = end; 
        if(uri.find('/', end + 1) == std::string::npos){
            impl_->path.push_back(uri.substr(end + 1, uri.length()));
        }
    }
    return true;
   
}


std::string uri::get_scheme()               const { return impl_->scheme; } 
std::string uri::get_host()                 const { return impl_->host; }
uint16_t    uri::get_port()                 const { return impl_->port; }
std::vector<std::string>  uri::get_path()   const { return impl_->path; }


int main(){
    uri a;
    auto if_true = a.parseuri("http:://www.baidu.com:80/foo/bar/ui/abc");

    std::cout << a.get_scheme() << std::endl;
    std::cout << a.get_host() << std::endl;
    std::cout << a.get_port() << std::endl;
    
    auto paths = a.get_path();
    for(auto i : paths){
        std::cout << i << std::endl;
    } 
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值