前一段时间在工作过程中遇到一个场景需要将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类型的字符串,下图是大体流程图

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

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

函数这里传入的四个参数分别是输入字符串,分割符,遇到空格处理(保留,跳过),结果类型(保留空值,不保留)

可以看到google根据传入的分割符的长度做了两种处理方式,说是做了两种处理方式,但其实就是讲分割符一个看成单个字符char,一个看成std::string字符串而已,这与SplitStringT模板的具体实现有关。下面重头戏来了,看下SplitStringT是如何实现的

template<typename Str, typename OutputStringType, typename DelimiterType>
static std::vector<OutputStringType> SplitStringT(
BasicStringPiece<Str> str,
DelimiterType delimiter,
WhitespaceHandling whitespace,
SplitResult result_type) {
std::vector<OutputStringType> result;
if (str.empty())
return result; size_t start = 0;
while (start != Str::npos) {
size_t end = FindFirstOf(str, delimiter, start); BasicStringPiece<Str> 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<Str>(), TRIM_ALL); if (result_type == SPLIT_WANT_ALL || !piece.empty())
result.push_back(PieceToOutputType<Str, OutputStringType>(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<Str>(), TRIM_ALL); if (result_type == SPLIT_WANT_ALL || !piece.empty())
result.push_back(PieceToOutputType<Str, OutputStringType>(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<typename Str>
BasicStringPiece<Str> TrimStringPieceT(BasicStringPiece<Str> input,
BasicStringPiece<Str> 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 <iostream>
#include <vector>
#include <string> 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<std::string> SplitString(std::string str,
std::string c,
bool skip_whitespace,
bool skip_empty)
{
std::vector<std::string> 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<std::string> result = SplitString("url=https://www.baidu.com", ".", true, false);
return 0;
}

Chromium base库分割字符串SplitString的更多相关文章

  1. VC/MFC分割字符串(SplitString)返回CStringArray

    引自:http://bbs.csdn.net/topics/60321228 原版: CStringArray* SplitString(CString string, char pattern) { ...

  2. 利用MySQL存储过程分割字符串

    (转)http://tec.5lulu.com/detail/104krn1e6p2w78d77.html 现有一段字符串,如apple,banana,orange,pears,grape,要把它按照 ...

  3. (三)Boost库之字符串处理

    (三)Boost库之字符串处理 字符串处理一直是c/c++的弱项,string_algo库很好的弥补了这一点. string_algo 库算法命名规则: 前缀i    : 有这个前缀表名算法的大小写不 ...

  4. C语言的本质(22)——C标准库之字符串操作

    编译器.浏览器.Office套件等程序的主要功能都是符号处理,符号处理功能在程序中占相当大的比例,无论多复杂的符号处理都是由各种基本的字符串操作组成的,下面介绍如何用C语言的库函数做字符串初始化.取长 ...

  5. c/c++分割字符串

    c++分割字符串: http://www.martinbroadhurst.com/how-to-split-a-string-in-c.html c分割字符串: http://www.martinb ...

  6. UDF_表值函数与标量函数的区别_分割字符串成单个的字符并返回表(插入到表中)

    UDF_区别_分割字符串成单个的字符并返回表(插入到表中) /* SQL表值函数和标量值函数的区别 实验环境:SQL Server 2014,参考maomao365有改编 在sqlserver中存储过 ...

  7. Delphi中stringlist分割字符串的用法

    Delphi中stringlist分割字符串的用法 TStrings是一个抽象类,在实际开发中,是除了基本类型外,应用得最多的. 常规的用法大家都知道,现在来讨论它的一些高级的用法. 1.CommaT ...

  8. C语言分割字符串

    最近在做一道C语言题目的时候需要用到分割字符串,本来想自己手写的,也不会很麻烦,但想到其他语言都有分割字符串的库函数,C语言怎么会没有呢?所以,在网上搜了一搜,果然有这样的函数,还是很好用的,在此总结 ...

  9. Android--split()分割字符串特殊用法

    split()分割字符串 1.不同环境下的区分 Java:分割字符串不能写成split("$")//$为要分割的字符Android:分割字符串需要加上中括号split(" ...

随机推荐

  1. apollo配置中心初探

    近在搞微服务框架的开发,需要有一个配置中心来满足统一管理业务应用以及组件的配置,在此期间也使用了多个配置中心比如:spring cloud config,自研的配置中心,当然还有apollo. spr ...

  2. [转] 打开 CMD 时自动执行命令

    [转] 打开 CMD 时自动执行命令 问题描述 在Windows中打开一个command-prompt时,我正在寻找一种方法来执行一些控制台命令,特别是设置一些命令别名. 例如,当打开command- ...

  3. 爬虫2:urllib

        了解即可,不好用   一. 概述   python内置的http请求库,包括4个模块,分别如下   urllib.request   请求模块 urllib.error       异常处理模 ...

  4. Parallelism VS Concurrency

     一个电脑/手机 有很多核,每一个核上运行一个任务,叫做 Parallelism. 只有一个核,通过任务调度,也可以实现 Concurrency.

  5. 设计简单登录界面(Java web)

    程序设计思想: 在Input.jsp中创建一个表格里边分别是课程名称,任课老师,教学地点,并分别用三个文本框来接受输入的三个属性, 并传到另外的Jsp页面中,又来接受三个数据,并判断传来的教师,与教室 ...

  6. jquery scrollTop()与scrollLeft()

    1.scrollLeft() scrollLeft() 方法设置或返回被选元素的水平滚动条位置. 提示:当滚动条位于最左侧时,位置是 0. 当用于返回位置时:该方法返回第一个匹配元素的滚动条的水平位置 ...

  7. Eclipse中的创建maven项目,无法添加src/main/java等source folder

    maven无法添加src/main/java 通过Eclipse创建Java Web项目,目录结构如下: 默认是只有src/main/resources 这个source folder 按照maven ...

  8. (二)Audio子系统之new AudioRecord()

    在上一篇文章<(一)Audio子系统之AudioRecord.getMinBufferSize>中已经介绍了AudioRecord如何获取最小缓冲区大小,接下来,继续分析AudioReco ...

  9. 线段树+单调栈+前缀和--2019icpc南昌网络赛I

    线段树+单调栈+前缀和--2019icpc南昌网络赛I Alice has a magic array. She suggests that the value of a interval is eq ...

  10. 使用webpack && react环境

    使用webpack webpack是一款模块化的打包工具,它认为所有的文件都是模块,包括js,css等等,版本为2.x推荐学习,1.x版本已废弃,不建议使用. 目前,facebook官方就是使用web ...