C++中string如何实现字符串分割函数split()——4种方法

2023-11-08

如:

string str1 = "This is a test";
string str2 = "This-is-a-test";
string str2 = "This+is+a+test";

我们如何将以上字符串按照某种分隔符( ,-,+),将其分割成四个子串,其值分别为 “This” “is” “a” “test” 。

一、使用stringstream

这里我们只需要用到 istringstream(字符串输入流) 构造字符串流,然后从字符串流中按照一定的格式读取数据即可。

通常我们使用 cin 从流中读取数据,而我们也可以使用 getline 读取,而后者在读取时可以选择接受的数据格式,其函数原型如下:

// istream & getline(char* buf, int bufSize);	// 读到 \n 为止
istream & getline(char* buf, int bufSize, char delim); //读到 delim 字符为止
				// \n 或 delim 都不会被读入 buf,但会被从文件输入流缓冲区中取走

 因此,我们可以按照此方式设计一个C++中的string split函数。

void Stringsplit(string str,const const char split)
{
	istringstream iss(str);	// 输入流
	string token;			// 接收缓冲区
	while (getline(iss, token, split))	// 以split为分隔符
	{
		cout << token << endl; // 输出
	}
}

如此,我们就设计出了我们的Stringsplit() 函数。该函数有以下 2 种语法格式

void Stringsplit(string str,const const char split);
// 默认将传入的字符串str以split为分隔符进行分割,并将得到的子串打印在屏幕上,无返回值
void Stringsplit(string str, const const char split,vector<string>& rst);
// 默认将传入的字符串str以split为分隔符进行分割,    不会将子串打印在屏幕上,无返回值
// 					分割的子串将会保存在rst数组中被带出函数。

 以上,我们简单的设计了一种C++中的分割字符串的函数,下面来看一个测试用例:

int main() {

	string str("This is a test");
	Stringsplit(str, ' ');		// 打印子串
	
	vector<string> strList;
	string str2("This-is-a-test");
	Stringsplit(str2, '-', strList);	// 将子串存放到strList中
	for (auto s : strList)
		cout << s << " ";
	cout << endl;

	return 0;
}
# 输出
This
is
a
test
This is a test

二、使用string类提供的find方法与substr方法

find函数原型: 

size_type find( const basic_string& str, size_type pos = 0 ) const;

参数:
str - 要搜索的 string , pos - 开始搜索的位置
返回值
找到的子串的首字符位置,或若找不到这种子串则为 npos 。

substr函数原型: 

basic_string substr( size_type pos = 0, size_type count = npos ) const;

参数:
pos - 要包含的首个字符的位置 ,count - 子串的长度
返回值
含子串 [pos, pos+count) 的 string 。

由以上两个函数我们便可以设计出我们的Stringsplit()来。同时,因为find()函数查找的可以是字符串,因此我们的分隔符可以是单个的字符,也可以是一个字符串。 

// 使用字符分割
void Stringsplit(const string& str, const char split, vector<string>& res)
{
	if (str == "")		return;
	//在字符串末尾也加入分隔符,方便截取最后一段
	string strs = str + split;
	size_t pos = strs.find(split);

	// 若找不到内容则字符串搜索函数返回 npos
	while (pos != strs.npos)
	{
		string temp = strs.substr(0, pos);
		res.push_back(temp);
		//去掉已分割的字符串,在剩下的字符串中进行分割
		strs = strs.substr(pos + 1, strs.size());
		pos = strs.find(split);
	}
}
// 使用字符串分割
void Stringsplit(const string& str, const string& splits, vector<string>& res)
{
	if (str == "")		return;
	//在字符串末尾也加入分隔符,方便截取最后一段
	string strs = str + splits;
	size_t pos = strs.find(splits);
	int step = splits.size();

	// 若找不到内容则字符串搜索函数返回 npos
	while (pos != strs.npos)
	{
		string temp = strs.substr(0, pos);
		res.push_back(temp);
		//去掉已分割的字符串,在剩下的字符串中进行分割
		strs = strs.substr(pos + step, strs.size());
		pos = strs.find(splits);
	}
}

下面是一个测试用例:

int main()
{
	vector<string> strList;
	string str("This-is-a-test");
	Stringsplit(str, '-', strList);
	for (auto s : strList)
		cout << s << " ";
	cout << endl;

	vector<string> strList2;
	string str2("This%20is%20a%20test");
	Stringsplit(str2, "%20", strList2);
	for (auto s : strList2)
		cout << s << " ";
	cout << endl;
	return 0;
}
# 输出
This is a test
This is a test

三、使用C库函数strtok

char* strtok( char* str, const char* delim );

参数:
str - 指向要记号化的空终止字节字符串的指针
delim - 指向标识分隔符的空终止字节字符串的指针
返回值:
指向下个记号起始的指针,或若无更多记号则为空指针。

需要注意的是,该函数使用一个全局的静态变量来保存每次分割后的位置,因此在多线程中是不安全的,这里我们也可以选择使用它的线程安全版本

 char *strtok_r(char *str, const char *delim, char **saveptr); 。
void Stringsplit(const string& str, const string& split, vector<string>& res)
{
	char* strc = new char[str.size() + 1];
	strcpy(strc, str.c_str());   // 将str拷贝到 char类型的strc中
	char* temp = strtok(strc, split.c_str());
	while (temp != NULL)
	{
		res.push_back(string(temp));		
		temp = strtok(NULL, split.c_str());	// 下一个被分割的串
	}
	delete[] strc;
}

如此,我们的使用 strtok 版本的Stringsplit() 就完成了。不过,我们使用这种方法实现的字符串分割函数只能根据字符来分割,而我们传入的参数是字符串类型,这样可能会对函数的使用这造成误导(注:参数传入字符串用的双引号,传入字符用的单引号),因此我们也可以使用下面的方法封装一个参数是字符类型的函数。

void Stringsplit(const string& str, const char split, vector<string>& res)
{
	Stringsplit(str, string(1,split), res);	// 调用上一个版本的Stringsplit()
}

 下面给出一个测试用例,我们分别使用单/双引号传入分割的限定字符。

int main()
{
	vector<string> strList;
	string str("This+is+a+test");
	Stringsplit(str, '+', strList);
	for (auto s : strList)
		cout << s << " ";
	cout << endl;

	vector<string> strList2;
	string str2("This-is-a-test");
	Stringsplit(str2, "-", strList2);
	for (auto s : strList2)
		cout << s << " ";
	cout << endl;


	return 0;
}

四、使用regex_token_iterator(正则表达式)

正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。 

而在C++的正则中,把这种操作称为Tokenize分词(或者叫切割)。这种操作刚好可以满足我们的需求,用模板类regex_token_iterator<>提供分词迭代器,可以完成字符串的分割。

void Stringsplit(const string& str, const string& split, vector<string>& res)
{
	//std::regex ws_re("\\s+"); // 正则表达式,匹配空格 
	std::regex reg(split);		// 匹配split
	std::sregex_token_iterator pos(str.begin(), str.end(), reg, -1);
	decltype(pos) end;              // 自动推导类型 
	for (; pos != end; ++pos)
	{
		res.push_back(pos->str());
	}
}

测试用例:

int main()
{
	// 单个字符分词
	vector<string> strList;
	string str("This is a test");
	Stringsplit(str," ", strList);
	for (auto s : strList)
		cout << s << " ";
	cout << endl;

	// 使用字符串分词
	vector<string> strList2;
	string str2("ThisABCisABCaABCtest");
	Stringsplit(str2, "ABC", strList2);
	for (auto s : strList2)
		cout << s << " ";
	cout << endl;
}
# 输出
This is a test
This is a test

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++中string如何实现字符串分割函数split()——4种方法 的相关文章

随机推荐

  • Windows下查看Android手机APP日志

    1 JDK环境搭建 略 在命令行窗口输入 java version 回车后显示版本号则表示JDK环境安装成功 2 配置adb环境 点击下方打开官网链 下载适用于Windows的SDK Platform Tools 下载成功后解压该文件 ht
  • 定时任务动态管理-Scheduled

    文章目录 前言 一 架构流程图 二 代码实现流程 1 引入库 2 代码流程 前言 定时任务动态管理分为两种方式 方式一 Web前台配置Trigger触发器 关联Cron ThreadPoolTaskScheduler类创建Scheduler
  • 蓝桥杯每日一题2023.9.21

    蓝桥杯2021年第十二届省赛真题 异或数列 C语言网 dotcpp com 题目描述 Alice 和 Bob 正在玩一个异或数列的游戏 初始时 Alice 和 Bob 分别有一个整数 a 和 b 有一个给定的长度为 n 的公共数列 X1 X
  • 与ajax类似的技术,介绍Ajax与jQuery技术

    Ajxs技术 异步的JavaScript与XML 已有多种技术的组合 Ajax的优点是什么 1 可以实现客户端的异步请求操作2 进而在不需要刷新页面的情况下与服务器进行通信 减少用户的等待时间3 减轻服务器和带宽的负担 提供更好的服务响应
  • linux socket bind 内核详解,Socket与系统调用深度分析(示例代码)

    1 什么是系统调用 操作系统通过系统调用为运行于其上的进程提供服务 当用户态进程发起一个系统调用 CPU 将切换到 内核态 并开始执行一个 内核函数 内核函数负责响应应用程序的要求 例如操作文件 进行网络通讯或者申请内存资源等 在Linux
  • 在 CentOS 上安装 Docker 引擎

    在 CentOS 上安装 Docker 引擎 预计阅读时间 11分钟 要在 CentOS 上开始使用 Docker 引擎 请确保 满足先决条件 然后 安装 Docker 先决条件 操作系统要求 要安装 Docker Engine 您需要 C
  • 双向广搜(bfs)

    双向广度优先搜索 广度优先搜索遵循从初始结点开始一层层扩展直到找到目标结点的搜索规则 它只能较好地解决状态不是太多的情况 承受力很有限 如果扩展结点较多 而目标结点又处在较深层 采用前文叙述的广度搜索解题 搜索量巨大是可想而知的 往往就会出
  • GDI+ Graphics绘文字定位不准,显示偏差问题

    拿来主义人员速达 取一般的版式 TGPStringFormat 对象 使用可以达到精准定位显示效果 format GenericTypographic MFC开发中需要自绘控件 使用Graphics绘文字时出现位置偏右偏下问题 显示效果如下
  • JSR-303使用依赖jar包

    jboss logging 3 1 0 GA jar slf4j api 1 5 8 jar hibernate validator 4 3 0 Final jar validation api 1 1 0 Alpha1 jar java
  • springboot 定时任务(线程配置,并行【同步】、异步等)

    定时任务 实现方式 SpringBoot自带的Scheduled 可以将它看成一个轻量级的Quartz 而且使用起来比Quartz简单许多 本文主要介绍 执行方式 单线程 串行 多线程 并行 创建定时任务 Component EnableS
  • 数据库主从同步的作用是什么,如何解决数据不一致问题?

    Redis是一种高性能的内存数据库 而MySQL是基于磁盘文件的关系型数据库 相比于Redis来说 读取速度会慢一些 但是功能强大 可以用于存储持久化的数据 在实际工作中 我们常常将Redis作为缓存与MySQL配合来使用 当有数据访问请求
  • Android 使用Lottie的三个小技巧

    Android 使用Lottie的三个小技巧 Shawn 文章目录 Android 使用Lottie的三个小技巧 I 开启硬件加速 II 通过添加AnimatorListener来控制动画行为 III 通过设置播放速度来实现动画倒放 I 开
  • 构建天气数据API:使用Scrapyd提供实时天气信息接口

    目录 1 天气数据API的重要性 2 选择合适的气象数据源 3 构建天气数据爬虫 4 使用Scrapyd进行
  • 4.3.1 位置变化动作

    4 3 1 位置变化动作 2013 05 21 10 12 火烈鸟网络科技 人民邮电出版社 我要评论 0 字号 T T Cocos2d x高级开发教程 第4章动作 在这一章中 我们将为大家详细介绍各种动作的使用方法 读完本章后 读者将会学到
  • App Transport Security has blocked a cleartext HTTP

    问题 App Transport Security has blocked a cleartext HTTP http resource load since it is insecure Temporary exceptions can
  • linux查找含有指定字符串的文件

    1 使用find进行查找 find oracle apache tomcat 8 5 59 xml xargs grep 1521 2 使用grep查找 grep rn 搜索的内容 路径
  • linux终端Bash换成zsh后,环境变量失效的解决方案

    安装了oh my zsh后 发现node ng什么的命令都失效了 第一反映是环境变量失效 忘记了怎么配置 Search on the Internet half an hour 说多了都是泪 一直找不到解决方法 最终问了项目老大 一句话点明
  • 五.安装gitlab

    1 下载安装 gitlab ce 15 9 1 ce 0 el7 x86 64 rpm 下载安装包 wget https mirrors tuna tsinghua edu cn gitlab ce yum el7 gitlab ce 15
  • python连接oracle数据库查询

    直接上源码说明吧 如下 开头引入必须的插件 连接oracle需要导入cx Oracle coding utf8 import cx Oracle import sys os from selenium import webdriver 编码
  • C++中string如何实现字符串分割函数split()——4种方法

    如 string str1 This is a test string str2 This is a test string str2 This is a test 我们如何将以上字符串按照某种分隔符 将其分割成四个子串 其值分别为 Thi