前一段时间在工作过程中遇到一个场景需要将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. php 递归数据,三维数组转换二维

    public function sortarea($area, $parent_id = 0, $lev = 1){ static $list; foreach($area as $v){ if($v ...

  2. [Objective-C语言教程]类和对象(24)

    Objective-C编程语言的主要目的是为C编程语言添加面向对象,类是Objective-C的核心特性,支持面向对象编程,通常称为用户定义类型. 类用于指定对象的形式,它将数据表示和方法组合在一起, ...

  3. Linux(Ubuntu)新建用户只有一个$问题

    参考自: http://www.cnblogs.com/ylan2009/articles/2321177.html 1.用root登录操作 2.查看/etc/passwd文件中新建用户的权限 有没有 ...

  4. 调用jdbc已经写成的方法----jdbc工具类抽取方式三

    package jdbc_demo3; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.R ...

  5. XMPPFramework核心类介绍

    XMPPFramework结构 在进入下一步之前,先给大家讲讲XMPPFramework的目录结构,以便新手们更容易读懂文章.我们来看看下图: 虽然这里有很多个目录,但是我们在开发中基本只关心Core ...

  6. 电信10兆指的是多少Mbps

    一般电信10兆(10Mbps)指的是:下载速度最大在1.25MB/s 1Mbps(兆位/秒)     =     0.125MB/S(兆字节/秒) 8Mbps(兆位/秒)     =     1MB/ ...

  7. Swagger2使用记录

    1. Swagger2使用记录 1.1. Bean配置文件 @Configuration public class Swagger2 { @Bean public Docket createRestA ...

  8. 1. C++11保证稳定性与兼容性

    1.1 __func__预定义标识符 在c99中,__func__基本功能是返回所在函数的名字,c++11中允许使用在类或结构体中. #include <iostream> using n ...

  9. Pycharm 报错 AttributeError: module 'pip' has no attribute 'main'

    1.打开文件packaging_tool.py: D:\Program files\pycharm\PyCharm 2016.3.2\helpers\packaging_tool.py 2.添加导入: ...

  10. git --mixed --soft --hard之间的区别

    git reset --mixed:此为默认方式,不带任何参数的git reset,即时这种方式,它回退到某个版本,只保留源码,回退commit和add信息git reset --soft:回退到某个 ...