博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Chromium base库分割字符串SplitString
阅读量:6261 次
发布时间:2019-06-22

本文共 5237 字,大约阅读时间需要 17 分钟。

前一段时间在工作过程中遇到一个场景需要将http response中的request header中的cookie字段取出并进行解析,但是手头没有解析cookie的工具类,同时cookie的表现就是个字符串,于是想到手动分割

但是在C++的标准库中,并没有提供类似split的函数,在有些时候可能会很不方便,今天就看看google大佬是如何实现字符串的分割的。
在chromium的base库中有提供和字符串相关的函数,在base/strings/string_split.h和base/strings/string_split.cc中定义了SplitString函数用于分割std::string类型的字符串,下图是大体流程图
928542-20190109130652299-1037440851.png

std::vector
SplitString(StringPiece input, StringPiece separators, WhitespaceHandling whitespace, SplitResult result_type) { if (separators.size() == 1) { return SplitStringT
( input, separators[0], whitespace, result_type); } return SplitStringT
( input, separators, whitespace, result_type);}

其中StringPiece是google定义的一种字符串类型,是对std::string的一种封装,这里就不再多说,可以直接看成std::string

函数这里传入的四个参数分别是输入字符串,分割符,遇到空格处理(保留,跳过),结果类型(保留空值,不保留)
可以看到google根据传入的分割符的长度做了两种处理方式,说是做了两种处理方式,但其实就是讲分割符一个看成单个字符char,一个看成std::string字符串而已,这与SplitStringT模板的具体实现有关。下面重头戏来了,看下SplitStringT是如何实现的

template
static std::vector
SplitStringT( BasicStringPiece
str, DelimiterType delimiter, WhitespaceHandling whitespace, SplitResult result_type) { std::vector
result; if (str.empty()) return result; size_t start = 0; while (start != Str::npos) { size_t end = FindFirstOf(str, delimiter, start); BasicStringPiece
piece; if (end == Str::npos) { piece = str.substr(start); start = Str::npos; } else { piece = str.substr(start, end - start); start = end + 1; } if (whitespace == TRIM_WHITESPACE) piece = TrimString(piece, WhitespaceForType
(), TRIM_ALL); if (result_type == SPLIT_WANT_ALL || !piece.empty()) result.push_back(PieceToOutputType
(piece)); } return result;}

模板参数的三个定义分别是<传入被分割字符串的类型,输出vector的模板类型,分界符类型>,函数的四个参数和上面说的相同,其中第三个第四个参数主要是对空值和空格的取舍。

Str::npos指的是size_t的最大值,也就是说在这个函数中为了避免字符串过长导致函数内部使用的startend发生溢出。
最基本就是循环遍历原始字符串,主要使用到了FindFirstOf函数,函数FindFirstOf的实现如下(只看分界符是单个字符char的情况)

size_t FindFirstOf(StringPiece piece, char c, size_t pos) {  return piece.find(c, pos);}

这里的find函数和std::stringfind函数功能一致,从当前pos位置开始想后查询c字符,找到第一个并返回其所在位置。如果找到了就更新end的值,然后取startend之间的子字符串,更新start的值。如果找到下一个分界符了,这个函数返回result就结束了。

剩下最后的部分就是对空格和空值的取舍,下面是取舍部分的代码,取自SplitStringT函数

if (whitespace == TRIM_WHITESPACE)      piece = TrimString(piece, WhitespaceForType
(), TRIM_ALL); if (result_type == SPLIT_WANT_ALL || !piece.empty()) result.push_back(PieceToOutputType
(piece));

空值取舍就是一个判断,这里不再描述,就只看空格取舍,WhitespaceForType<Str>()主要是提供一个模板空格,根据传入的Str类型不同空格也有可能不同,而TRIM_ALL的主要作用如下

enum TrimPositions {  TRIM_NONE     = 0,  TRIM_LEADING  = 1 << 0,  TRIM_TRAILING = 1 << 1,  TRIM_ALL      = TRIM_LEADING | TRIM_TRAILING,};

用于区分空格类型,头部空格和尾部空格。默认是TRIM_ALL全部。下面是TrimString函数的实现

StringPiece TrimString(StringPiece input,                       StringPiece trim_chars,                       TrimPositions positions) {  return TrimStringPieceT(input, trim_chars, positions);}
template
BasicStringPiece
TrimStringPieceT(BasicStringPiece
input, BasicStringPiece
trim_chars, TrimPositions positions) { size_t begin = (positions & TRIM_LEADING) ? input.find_first_not_of(trim_chars) : 0; size_t end = (positions & TRIM_TRAILING) ? input.find_last_not_of(trim_chars) + 1 : input.size(); return input.substr(begin, end - begin);}

用的函数也和std::string的成员函数功能一致,是很简单的去除空格的方式。

附录

我略微整理了一下一个VS可直接编译运行的版本(几乎没啥改动就是了)

#include 
#include
#include
enum TrimPositions { TRIM_NONE = 0, TRIM_LEADING = 1 << 0, TRIM_TRAILING = 1 << 1, TRIM_ALL = TRIM_LEADING | TRIM_TRAILING,};size_t FindFirstOf(std::string piece, std::string c, size_t pos) { return piece.find(c, pos);}std::string TrimString(std::string input, TrimPositions positions) { size_t begin = (positions & TRIM_LEADING) ? input.find_first_not_of(" ") : 0; size_t end = (positions & TRIM_TRAILING) ? input.find_last_not_of(" ") + 1 : input.size(); return input.substr(begin, end - begin);}std::vector
SplitString(std::string str, std::string c, bool skip_whitespace, bool skip_empty) { std::vector
result; if (str.empty()) return result; size_t start = 0; while (start != std::string::npos) { size_t end = FindFirstOf(str, c, start); std::string piece; if (end == std::string::npos) { piece = str.substr(start); start = std::string::npos; } else { piece = str.substr(start, end - start); start = end + 1; } if (skip_whitespace) piece = TrimString(piece, TRIM_NONE); if (!skip_empty || !piece.empty()) result.push_back(piece); } return result;}int main(){ std::vector
result = SplitString("url=https://www.baidu.com", ".", true, false); return 0;}

转载于:https://www.cnblogs.com/lenomirei/p/10243679.html

你可能感兴趣的文章
rsync数据同步工具
查看>>
文件上传限制文件类型
查看>>
基于Android平台的会议室管理系统具体设计说明书
查看>>
Linux常见命令(四)——mkdir
查看>>
正则表达式基础知识
查看>>
Web下的HTTPS应用
查看>>
perl数组的长度与元素个数
查看>>
Netty线程模型
查看>>
『Kaggle』Sklearn中几种分类器的调用&词袋建立
查看>>
017_nginx重定向需求
查看>>
[UWP]涨姿势UWP源码——RSS feed的获取和解析
查看>>
判断一个变量是否为空的方法
查看>>
linux 学习一:安装jdk和tomcat
查看>>
[js高手之路]html5 canvas动画教程 - 边界判断与反弹
查看>>
Lua--------------------unity3D与Slua融合使用
查看>>
IP视频通信中的"丢包恢复技术”(LPR)
查看>>
java序列化/反序列化之xstream、protobuf、protostuff 的比较与使用例子
查看>>
xcode编译报错unknown error -1=ffffffffffffffff Command /bin/sh failed with exit code 1
查看>>
linux定时任务crontab设置
查看>>
$.ajax返回的JSON格式的数据后无法执行success的解决方法
查看>>