文章目录
问题描述
假设我们有一个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在循环中)扫描二维码关注公众号,回复: 14722612 查看本文章
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'
(P1是s.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;
}
}