【C++】stringstream

stringstream 定义于头文件 <sstream>,它其实是个别名,具体定义如下:

cpp 复制代码
typedef basic_stringstream<char> stringstream;
<sstream> 定义了三个类:istringstream、ostringstream 和 stringstream,分别用来进行流的输入、输出和输入输出操作。本文以 stringstream 为主,介绍流的输入和输出操作。

<sstream> 主要用来进行数据类型转换,由于 <sstream> 使用 string 对象来代替字符数组(snprintf 方式),避免了缓冲区溢出的危险;而且,因为传入参数和目标对象的类型会被自动推导出来,所以不存在错误的格式化符号的问题。简单说,相比 C 编程语言库的数据类型转换,<sstream> 更加安全、自动和直接.

类模板 std::basic_stringstream 实现基于字符串的流上的输入与输出操作。它等效地存储一个 std::basic_string 的实例,并在其上进行输入与输出操作。继承图如下:

构造函数

创建一个对象,向对象输入字符串:

cpp 复制代码
stringstream ss;
ss << str;

在创建对象的时候使用字符串初始化:

cpp 复制代码
streamstring ss(str);

两种方式都可以创建对象,但创建后的对象用法不一样.

输出字符串

stringstream 可以将存储于内部的字符串输出,需要调用 str() 函数,不可直接输出:

c++ 复制代码
std::cout << ss.str() << std::endl;
// std::cout << ss << std::endl; 		// 错误不可直接输出

上面阐述了两种构造函数,利用不同的构造函数创建对象,对象具体的操作也不同:

第一种构造方式

c++ 复制代码
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
    stringstream ss1;
    ss1 << "fre";
    ss1 << "gre";
    cout << ss1.str() << endl;
    return 0;
}
/*
输出:
fregre
*/

第二种构造方式

c++ 复制代码
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
    string str("asd");
    stringstream ss2(str);
    cout << ss2.str() << endl;
    ss2 << "r";
    cout << ss2.str() << endl;
    ss2 << "13";
    cout << ss2.str() << endl;
    ss2 << "hy";
    cout << ss2.str() << endl;
    return 0;
}
/*
输出:
asd
rsd
r13
r13hy
*/

可以发现,利用第一种构造函数创建对象时,输入字符串后直接进行字符串拼接,而第二种构造方式,在进行字符串拼接时,首先把原本的字符串覆盖掉,之后再进行拼接。

如果不想原来的字符串被覆盖,则需要换一种构造方式,如下:

c++ 复制代码
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
    ostringstream ss("1 2 3 4 ", std::ios_base::ate);	// append 方式追加
    cout << ss.str() << endl;
    ss << "5 3 4";
    cout << ss.str() << endl;
    return 0;
}
/*
输出:
1 2 3 4 
1 2 3 4 5 3 4
*/

连接多个字符串

c++ 复制代码
#include <iostream>
#include <sstream>
#include <string>

int main() {
    std::stringstream ss;
    ss << "one" << " two" << " three" << " four";
    std::string str = ss.str();
    std::cout << str << std::endl; // 输出 "one two three four"
    return 0;
}

格式化输出

c++ 复制代码
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>

int main() {
    double pi = 3.14159265358979323846;
    std::stringstream ss;
    ss << std::fixed << std::setprecision(2) << pi;
    std::string str = ss.str();
    std::cout << str << std::endl; // 输出 "3.14"
    return 0;
}

检查 stringstream 对象是否为空

可以使用 str().empty() 函数来检查 stringstream 对象是否为空。

c++ 复制代码
#include <iostream>
#include <sstream>
#include <string>

int main() {
   int num = 12345;
   std::stringstream ss;

   if (ss.str().empty()) {
      std::cout << "Empty" << std::endl; // 输出 "Empty"
   }

   ss << num;

   if (!ss.str().empty()) {
      std::cout << "Not empty" << std::endl; // 输出 "Not empty"
   }

   return 0;
}

使用 getline 函数读取一整行

c++ 复制代码
#include <iostream>
#include <sstream>
#include <string>

int main() {
   std::string str = "one\ntwo\nthree\nfour";
   std::stringstream ss(str);
   std::string line;
   while (std::getline(ss, line)) {
      std::cout << line << std::endl;
   }
   return 0;
}

使用 peek 函数查看下一个字符

我们可以使用 peek 函数查看 stringstream 对象中的下一个字符,而不会改变 stringstream 对象的状态。下面是一个例子:

c++ 复制代码
#include <iostream>
#include <sstream>
#include <string>

int main() {
   std::string str = "12345";
   std::stringstream ss(str);
   char ch = ss.peek();
   std::cout << ch << std::endl; // 输出 '1'
   
   int num;
   ss >> num;
   std::cout << num << std::endl; // 输出 12345
   return 0;
}

使用 putback 函数将字符放回 stringstream 对象

c++ 复制代码
#include <iostream>
#include <sstream>
#include <string>

int main() {
   std::string str = "12345";
   std::stringstream ss(str);
   
   char ch;
   ss.get(ch);
   
   // 将字符 '1' 放回 stringstream 对象中
   ss.putback(ch);
   
   int num;
   ss >> num;
   
   // 输出 12345
   // 如果没有使用 putback 函数,则输出 2345
   std::cout << num << std::endl; 
   
   return 0;
}

修改、清空 stringstream 内容

stringstream 的内容可以通过 str() 函数进行修改、清空:

c++ 复制代码
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
    stringstream ss("fghewoo");
    cout << ss.str() << endl;
    // 修改内容
    ss.str("123456");
    cout << ss.str() << endl;
    // 清空内容
    ss.str("");
    cout << ss.str() << endl;
    return 0;
}
/*
输出:
fghewoo
123456

*/

//ss.clear(); // 清空状态位(例如错误标志)

利用 stringstream 去除字符串空格

stringstream 默认是以空格来分割字符串的,利用 stringstream 去除字符串空格非常方便:

c++ 复制代码
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
    stringstream ss("2 dfjho 43");
    cout << ss.str() << endl;
	cout<< endl;
    string str;
    while (ss >> str)
    {
        cout << str << endl;
    }
    return 0;
}
/*
输出:
2 dfjho 43

2 
dfjho 
43
*/

利用 stringstream 指定字符分割字符串

上面描述了利用 stringstream 去除字符串空格,其实就是利用空格来分割字符串,同样,也可以指定其他字符对字符串进行分割,这需要与 getline() 函数搭配使用,下面以逗号分割字符串为例:

c++ 复制代码
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
    string source = "abc,123,<!>";
    stringstream ss(source);
    cout << ss.str() << endl;
	cout<< endl;
    string str;
    while (getline(ss, str, ','))
    {
        cout << str << endl;
    }
    return 0;
}
/*
输出:
abc,123,<!>

abc
123
<!>
*/

上述代码以逗号作为分割依据来分割字符串,同样的还可以扩展到其他字符。

逐个提取数据

你可以使用 stringstream 来逐个提取以特定格式存储在字符串中的数据,例如:

c++ 复制代码
#include <sstream>
#include <iostream>
 
int main() {
    std::string data = "John 25 Programmer";
    std::stringstream ss(data);
    
    std::string name;
    int age;
    std::string occupation;
    
    ss >> name >> age >> occupation;
    
    std::cout << "Name: " << name << std::endl;
    std::cout << "Age: " << age << std::endl;
    std::cout << "Occupation: " << occupation << std::endl;
}

这里,stringstream 会根据空白字符自动分割字符串,并按照顺序将值赋给相应的变量。

运行结果:

Name: John
Age: 25
Occupation: Programmer

向字符串中逐个插入数据

stringstream 还可以往一个字符串中逐项插入数据,通过对流进行格式化,可以方便地构建具有复杂格式的字符串。

c++ 复制代码
#include <sstream>
#include <iostream>
 
int main() {
    std::stringstream ss;
    
    std::string name = "John";
    int age = 30;
    double salary = 60000.5;
    
    ss << "Name: " << name << ", Age: " << age << ", Salary: " << salary;
    
    std::string result = ss.str();
    std::cout << result << std::endl;
}

这里生成了一个包含多个变量值的字符串,变量之间由逗号和空格分隔。

运行结果:

Name: John, Age: 30, Salary: 60000.5

类型转换

使用stringstream将数字转换为字符串

c++ 复制代码
#include <sstream>
#include <iostream>
#include <string>
 
int main() {
    int num = 123;
    std::stringstream ss;
    ss << num; // 将整数放入流中
    std::string str = ss.str(); // 使用str()函数 从流中提取字符串
    std::cout << str << std::endl; // 输出:123
}

使用stringstream将字符串转换为数值类型

c++ 复制代码
#include <sstream>
#include <iostream>
#include <string>
 
int main() {
    std::string str = "456";
    std::stringstream ss(str); // 初始化stringstream
    int num;
    ss >> num; // 从流中提取整数
    std::cout << num << std::endl; // 输出:456
}

自动实现数据类型的转换

在 C++ 中,字符串流(stringstream)是一种特殊的流类,它允许将字符串作为输入和输出流进行处理。字符串流提供了一种方便的方式,可以将字符串与其他基本类型进行转换、拼接、解析等操作。

实例:

c++ 复制代码
#include<iostream>
#include<sstream>
using namespace std;
int main() {
    string s="aaa";
    stringstream line;
    line<< s;
    line << 1;//int
    line<<0.12; //float
    line<<'b'; //char
    cout<<line.str()<<endl;
    //结果为:aaa10.12b
    return 0;
}

练习

计算字符串中的单词个数

输入:"hello world c plus plus"
输出:5 
c++ 复制代码
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
	string str = "hello world c plus plus";
	int count = 0;
	stringstream ss(str);
	string word;
	while (ss >> word)
		count++;
	cout << count << endl;
	return 0;
}

反转字符串中的单词

151. 反转字符串中的单词

c++ 复制代码
class Solution {
public:
    string reverseWords(string s) 
    {
         string res,temp;
         stringstream ss(s);
         while(ss>>temp)
         {
            res = temp + " " + res;
         }
         if(!res.empty())
         {
            res.pop_back();
         }
         return res;
    }
};

使用 stringstream 实现整数排序

要求把输入保存到在一个stringstream对象中,再这10个整数放到一个整型数组中,将整型数组按大小排序,然后再存回到stringstream对象中。

要使用 stringstream 实现整数排序,你需要按照以下步骤操作:

  1. 初始化一个 stringstream 对象,并用输入的整数填充它。
  2. 将 stringstream 中的整数读取到一个整型数组中。
  3. 对该数组进行排序。
  4. 清空 stringstream 对象并将排序后的整数再放回 stringstream 中。
c++ 复制代码
#include <iostream>
#include <sstream>
#include <algorithm>
#include <iterator>
int main() {
    // 示例输入,10个整数
    std::string input = "10 3 5 7 2 8 6 9 1 4";
    std::stringstream ss(input);
    // 创建一个足够大的整型数组
    const int SIZE = 10;
    int numbers[SIZE];
    // 从 stringstream 读入整数到数组中
    for (int i = 0; i < SIZE; ++i) {
        ss >> numbers[i];
    }
    // 对数组进行排序
    std::sort(numbers, numbers + SIZE);
    // 清空并重置 stringstream
    ss.str("");
    ss.clear();
    // 将排序后的整数放回 stringstream
    for (int i = 0; i < SIZE; ++i) {
        ss << numbers[i] << " ";
    }
    // 输出结果,展示排序后的数字序列
    std::cout << "Sorted numbers: " << ss.str() << std::endl;
    return 0;
}

参考博文:

https://blog.csdn.net/weixin_45867382/article/details/122109133

https://blog.csdn.net/m0_64267361/article/details/135999544

https://blog.csdn.net/weixin_45031801/article/details/136921743

https://blog.csdn.net/m0_75273136/article/details/134712001

https://blog.csdn.net/sinat_28305511/article/details/131237559

相关推荐
可均可可21 分钟前
C++之OpenCV入门到提高004:Mat 对象的使用
c++·opencv·mat·imread·imwrite
白子寰43 分钟前
【C++打怪之路Lv14】- “多态“篇
开发语言·c++
小芒果_011 小时前
P11229 [CSP-J 2024] 小木棍
c++·算法·信息学奥赛
gkdpjj1 小时前
C++优选算法十 哈希表
c++·算法·散列表
王俊山IT1 小时前
C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(5)
开发语言·c++·笔记·学习
-Even-1 小时前
【第六章】分支语句和逻辑运算符
c++·c++ primer plus
我是谁??2 小时前
C/C++使用AddressSanitizer检测内存错误
c语言·c++
发霉的闲鱼2 小时前
MFC 重写了listControl类(类名为A),并把双击事件的处理函数定义在A中,主窗口如何接收表格是否被双击
c++·mfc
小c君tt2 小时前
MFC中Excel的导入以及使用步骤
c++·excel·mfc
xiaoxiao涛2 小时前
协程6 --- HOOK
c++·协程