「C/C++」C++ 标准库 之 #include<sstream> 之 std::istringstream

在这里插入图片描述

✨博客主页
何曾参静谧的博客(✅关注、👍点赞、⭐收藏、🎠转发)
📚全部专栏(专栏会有变化,以最新发布为准)
「Win」Windows程序设计「IDE」集成开发环境「定制」定制开发集合
「C/C++」C/C++程序设计「DSA」数据结构与算法「UG/NX」NX二次开发
「QT」QT5程序设计「File」数据文件格式「UG/NX」BlockUI集合
「Py」Python程序设计「Math」探秘数学世界「PK」Parasolid函数说明
「Web」前后端全栈开发「En」英语从零到一👍占位符
「AI」人工智能大模型「书」书籍阅读笔记

深入解析 std::istringstream:C++ 字符串流的高效使用指南

1. 概述

std::istringstream 是 C++ 标准库中的一个重要类,属于 <sstream> 头文件提供的字符串流工具之一。它允许程序员将字符串作为输入流来处理,提供了类似于从文件或标准输入读取数据的接口,但数据源是内存中的字符串。

1.1 基本概念

  • 输入字符串流:将现有的字符串转换为可读取的流
  • 继承自 std::istream:可以使用所有 istream 的操作方法
  • 内存操作:完全在内存中完成,无I/O开销
  • 类型安全:提供类型安全的字符串到其他数据类型的转换

1.2 主要用途

  1. 字符串解析和分割
  2. 数据类型转换(字符串到数值等)
  3. 格式化输入处理
  4. 文本数据处理和转换
  5. 实现复杂字符串操作

2. 基本用法

2.1 创建 istringstream 对象

#include <sstream>
#include <string>

// 方法1:默认构造 + 设置字符串
std::istringstream iss1;
iss1.str("Hello World 123 4.5");

// 方法2:构造时直接初始化
std::string data = "42 3.14 Hello";
std::istringstream iss2(data);

// 方法3:使用移动语义
std::string input = "Move this string";
std::istringstream iss3(std::move(input));
// 注意:此时input的内容被移动,变为未定义状态

2.2 基本读取操作

std::istringstream iss("123 456 7.89 hello");

int a, b;
double d;
std::string s;

iss >> a >> b >> d >> s;  // 依次提取不同类型的数据

std::cout << a << ", " << b << ", " << d << ", " << s << std::endl;
// 输出: 123, 456, 7.89, hello

2.3 检查流状态

std::istringstream iss("100 200 three");

int x, y, z;
iss >> x >> y;  // 成功读取两个整数

if (iss >> z) {  // 尝试读取第三个整数会失败
    std::cout << "读取成功: " << z << std::endl;
} else {
    std::cout << "读取失败" << std::endl;
    iss.clear();  // 清除错误状态
}

// 检查流状态标志
if (iss.fail()) {
    std::cout << "流处于失败状态" << std::endl;
}

3. 高级用法

3.1 字符串分割

std::string text = "apple,orange,banana,grape";
std::istringstream iss(text);
std::string token;

while (std::getline(iss, token, ',')) {
    std::cout << "分割得到: " << token << std::endl;
}
/* 输出:
分割得到: apple
分割得到: orange
分割得到: banana
分割得到: grape
*/

3.2 处理多行文本

std::string multiLine = "第一行\n第二行\n第三行";
std::istringstream iss(multiLine);
std::string line;

while (std::getline(iss, line)) {
    std::cout << "行内容: " << line << std::endl;
}

3.3 类型安全转换

std::string numberStr = "1234";
std::istringstream iss(numberStr);
int value;

if (iss >> value) {
    std::cout << "转换成功: " << value << std::endl;
} else {
    std::cout << "转换失败" << std::endl;
}

3.4 与 std::ws 结合使用(跳过空白)

std::string spaced = "   123   \t  456  ";
std::istringstream iss(spaced);
int a, b;

iss >> std::ws >> a >> std::ws >> b;  // 自动跳过前导空白
std::cout << a << ", " << b << std::endl;  // 输出: 123, 456

4. 错误处理和验证

4.1 完整数据验证

std::string input = "123abc";
std::istringstream iss(input);
int number;
char remaining;

if (iss >> number && !(iss >> remaining)) {
    std::cout << "有效整数: " << number << std::endl;
} else {
    std::cout << "无效输入" << std::endl;
    iss.clear();  // 清除错误状态以便后续操作
}

4.2 处理多种错误情况

std::string test = "123 456.78 abc 789";
std::istringstream iss(test);

int i;
double d;
std::string s;
int j;

iss >> i;  // 成功
if (iss.fail()) { /* 处理错误 */ }

iss >> d;  // 成功
if (iss.fail()) { /* 处理错误 */ }

iss >> s;  // 成功
if (iss.fail()) { /* 处理错误 */ }

iss >> j;  // 成功
if (iss.eof()) {
    std::cout << "到达流末尾" << std::endl;
}

5. 性能考虑和最佳实践

5.1 重用 istringstream 对象

std::istringstream iss;  // 创建一次
std::string input;

for (const auto& str : {"123", "456", "789"}) {
    iss.clear();      // 清除状态
    iss.str(str);     // 设置新字符串
    int value;
    iss >> value;
    // 处理value...
}

5.2 避免不必要的拷贝

std::string largeData = GetLargeString();  // 获取大字符串

// 好方法:使用移动语义
std::istringstream iss(std::move(largeData));
// largeData现在为空,内容已移动

// 不好的方法:会创建拷贝
// std::istringstream iss(largeData);

5.3 与正则表达式比较

对于简单解析,istringstream 通常比正则表达式更高效:

// 使用istringstream
std::istringstream iss("123,456");
int a, b;
char comma;
iss >> a >> comma >> b;

// 使用正则表达式
std::regex pattern(R"((\d+),(\d+))");
std::smatch matches;
std::regex_match("123,456", matches);
// 需要额外转换为整数

6. 实际应用示例

6.1 配置文件解析

std::string config = "width=800\nheight=600\ntitle=My Application";
std::istringstream iss(config);
std::string line;

while (std::getline(iss, line)) {
    std::istringstream lineStream(line);
    std::string key, value;
    
    if (std::getline(lineStream, key, '=') && 
        std::getline(lineStream, value)) {
        std::cout << "配置项: " << key << " = " << value << std::endl;
    }
}

6.2 CSV 数据处理

std::string csvData = "John,Doe,30\nJane,Smith,25\nBob,Johnson,40";
std::istringstream iss(csvData);
std::string line;

while (std::getline(iss, line)) {
    std::istringstream lineStream(line);
    std::string firstName, lastName, ageStr;
    
    std::getline(lineStream, firstName, ',');
    std::getline(lineStream, lastName, ',');
    std::getline(lineStream, ageStr);
    
    int age = std::stoi(ageStr);
    std::cout << lastName << ", " << firstName << ": " << age << "岁" << std::endl;
}

6.3 复杂字符串解析

std::string complexInput = "Results: (42, 3.14), (17, 2.71), (9, 1.41)";
std::istringstream iss(complexInput);
std::string prefix;
char discard;
int x;
double y;

iss >> prefix >> discard;  // 读取"Results:"和'('

while (iss >> discard >> x >> discard >> y >> discard) {
    std::cout << "x=" << x << ", y=" << y << std::endl;
    if (iss.peek() == ')') break;  // 检查下一个字符
}

7. 常见问题与解决方案

7.1 混合使用 >> 和 getline

std::string input = "123\nHello World";
std::istringstream iss(input);
int num;
std::string line;

iss >> num;  // 读取数字
iss.ignore();  // 跳过换行符
std::getline(iss, line);  // 现在可以正确读取整行

std::cout << num << " | " << line << std::endl;

7.2 处理不同进制

std::string hexNum = "FF";
std::istringstream iss(hexNum);
int value;

iss >> std::hex >> value;  // 按十六进制读取
std::cout << "十进制值: " << value << std::endl;  // 输出255

7.3 自定义类型解析

struct Point {
    int x, y;
};

std::istream& operator>>(std::istream& is, Point& p) {
    char ch;
    if (is >> ch && ch == '(' && is >> p.x >> ch && ch == ',' && is >> p.y >> ch && ch == ')') {
        return is;
    }
    is.setstate(std::ios::failbit);
    return is;
}

std::string pointStr = "(10, 20)";
std::istringstream iss(pointStr);
Point p;

if (iss >> p) {
    std::cout << "解析成功: (" << p.x << ", " << p.y << ")" << std::endl;
}

8. 总结

std::istringstream 是 C++ 中处理字符串解析和转换的强大工具,它提供了:

  1. 类型安全的字符串转换:避免手写转换代码的错误
  2. 灵活的输入处理:支持各种格式的字符串解析
  3. 标准流接口:与C++其他流操作一致
  4. 高效的内存操作:无I/O开销

通过合理使用 std::istringstream,可以大大简化字符串处理任务,编写出更清晰、更健壮的代码。

何曾参静谧的博客(✅关注、👍点赞、⭐收藏、🎠转发)


在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS 1 #define _CSIDL_DESKTOPDIRECTORY 1 #include <stdio.h> #include <Shlobj.h> #include <iostream> #include <fstream> #include <string> #include <vector> #include <sstream> #include <windows.h> // 获取桌面路径函数 std::string GetDesktopPath() { char desktopPath[MAX_PATH]; if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, desktopPath))) { return std::string(desktopPath) + "\\"; } return ""; } int main() { // 获取桌面路径 std::string desktopPath = GetDesktopPath(); if (desktopPath.empty()) { std::cerr << "无法获取桌面路径!" << std::endl; return 1; } // 输入输出文件名 std::string inputFile = desktopPath + "input.txt"; std::string outputFile = desktopPath + "output.csv"; // 打开输入文件 std::ifstream inFile(inputFile); if (!inFile.is_open()) { std::cerr << "无法打开输入文件: " << inputFile << std::endl; return 1; } // 创建输出文件 std::ofstream outFile(outputFile); if (!outFile.is_open()) { std::cerr << "无法创建输出文件: " << outputFile << std::endl; return 1; } std::string line; // 写入CSV表头 outFile << "ID,Name,Score,Grade\n"; // 处理每行数据 while (std::getline(inFile, line)) { std::istringstream iss(line); int id, score; std::string name; char comma; // 解析数据 (格式: ID,Name,Score) if (iss >> id >> comma && std::getline(iss, name, ',') >> score) { // 添加额外处理逻辑(示例:计算等级) std::string grade = (score >= 90) ? "A" : (score >= 80) ? "B" : "C"; // 写入CSV行 outFile << id << "," << name << "," << score << "," << grade << "\n"; } } // 关闭文件 inFile.close(); outFile.close(); std::cout << "数据处理完成! 输出文件: " << outputFile << std::endl; return 0; } 修改这个这个代码处理的数据,改为S时间戳,V浮点数,C浮点数L_Wheel数值,R_Wheel数值
06-29
#include <iostream> #include <fstream> #include <istream> #include <sstream> #include <streambuf> #include <vector> #include <string> #include <stdlib.h> void printCsv(std::vector<std::string> line_data) { std::cout << line_data[0] // << atof(line_data[1].c_str()) // << atof(line_data[2].c_str()) << line_data[1] << line_data[2] << line_data[3] << std::endl; } int main() { std::ifstream csv_data("C:\\Users\\17718\\Desktop\\newtest.csv", std::ios::in); std::string line; if (!csv_data.is_open()) { std::cout << "Error: opening file fail" << std::endl; exit(1); } std::vector<std::string> words; //声明一个字符串向量 std::string word; // ------------读取数据----------------- // 读取标题行 std::getline(csv_data, line); std::istringstream sin; // 按行读取数据 while (std::getline(csv_data, line)) { // 清空vector,只存当前行的数据 words.clear(); sin.clear(); sin.str(line); while (std::getline(sin, word, ',')) //将字符串流sin中的字符读到field字符串中,以逗号为分隔符 { std::cout << word << std::endl; words.push_back(word); //将每一格中的数据逐个push } printCsv(words); } csv_data.close(); std::ofstream outFile; outFile.open("C:\\Users\\17718\\Desktop\\newtest.csv", std::ios::out | std::ios::trunc); // 写入标题行 outFile << "name" << ',' << "income" << ',' << "expenditure" << ',' << "addr" << std::endl; // ********写入两行数据********* // 写入字符串(数字) outFile << "zhangsan" << ',' << "3000" << ',' << "1200" << ',' << "中国 陕西省" << std::endl; // 写入浮点数(转为字符串) outFile << "lisi" << ',' << std::to_string(2032.1) << ',' << std::to_string(789.2) << ',' << "中国 北京市" << std::endl; outFile.close(); return 0; }
06-24
#include <iostream> #include <cmath> #include <chrono> #include <thread> #include <vector> #include <gmpxx.h> #include <fstream> #include <sstream> #include <iomanip> #include <mutex> #include <atomic> #include <sys/sysinfo.h> #include <sys/resource.h> #include <fstream> #include <unistd.h> #include <nvml.h> // NVIDIA GPU监控 std::mutex output_mutex; std::atomic<bool> stop_monitor(false); mpf_class pi_value(0, 0); // 高精度π值 std::atomic<int> iteration_count(0); // 获取CPU使用率 double get_cpu_usage() { static uint64_t last_total = 0, last_idle = 0; std::ifstream stat_file("/proc/stat"); std::string line; std::getline(stat_file, line); std::istringstream iss(line); std::string cpu; uint64_t user, nice, system, idle, iowait, irq, softirq, steal; iss >> cpu >> user >> nice >> system >> idle >> iowait >> irq >> softirq >> steal; uint64_t total = user + nice + system + irq + softirq + steal; uint64_t idle_time = idle + iowait; double usage = 0.0; if (last_total != 0) { uint64_t total_diff = total - last_total; uint64_t idle_diff = idle_time - last_idle; usage = 100.0 * (1.0 - static_cast<double>(idle_diff) / total_diff); } last_total = total; last_idle = idle_time; return usage; } // 获取内存使用率 double get_memory_usage() { struct sysinfo mem_info; sysinfo(&mem_info); double total = mem_info.totalram; double free = mem_info.freeram; return 100.0 * (1.0 - free / total); } // 获取GPU使用率 (NVIDIA) double get_gpu_usage() { nvmlReturn_t result; nvmlDevice_t device; unsigned int utilization; result = nvmlInit(); if (result != NVML_SUCCESS) return -1.0; result = nvmlDeviceGetHandleByIndex(0, &device); if (result != NVML_SUCCESS) { nvmlShutdown(); return -1.0; } result = nvmlDeviceGetUtilizationRates(device, &utilization); if (result != NVML_SUCCESS) { nvmlShutdown(); return -1.0; } nvmlShutdown(); return static_cast<double>(utilization.gpu); } // 资源监控线程函数 void monitor_resources() { while (!stop_monitor) { double cpu = get_cpu_usage(); double mem = get_memory_usage(); double gpu = get_gpu_usage(); { std::lock_guard<std::mutex> lock(output_mutex); std::cout << "\033[2K"; // 清除当前行 std::cout << "\r[资源监控] CPU: " << std::fixed << std::setprecision(1) << cpu << "% | " << "内存: " << mem << "% | " << "GPU: " << (gpu >= 0 ? std::to_string(static_cast<int>(gpu)) + "%" : "N/A"); std::cout.flush(); } std::this_thread::sleep_for(std::chrono::seconds(1)); } } // Chudnovsky算法计算π mpf_class chudnovsky_pi(unsigned int precision, unsigned int iterations) { mpf_set_default_prec(precision); mpf_class pi(0, precision); mpf_class sum(0, precision); mpf_class k1(13591409, precision); mpf_class k2(545140134, precision); mpf_class k3(-262537412640768000, precision); mpf_class k4(426880, precision); mpf_class k5(10005, precision); mpf_class sqrt_c(0, precision); k5 = sqrt(k5); sqrt_c = k4 * k5; mpz_class a(1); mpz_class b(1); mpz_class a_prime(1); mpz_class b_prime(1); for (unsigned int k = 0; k < iterations; k++) { mpf_class numerator(0, precision); mpf_class denominator(0, precision); if (k == 0) { a = 1; b = 1; } else { // 使用二进制分裂法优化计算 a_prime = (6*k-5)*(2*k-1)*(6*k-1); b_prime = k*k*k * k3 / 24; a *= a_prime; b *= b_prime; } numerator = k1 + k2 * k; denominator = a * b; sum += numerator / denominator; iteration_count = k + 1; // 每100次迭代显示进度 if (k % 100 == 0) { pi = sqrt_c / sum; std::lock_guard<std::mutex> lock(output_mutex); std::cout << "\n[计算进度] 迭代: " << k << "/" << iterations << " | 当前π值: " << std::setprecision(15) << pi << std::endl; } } pi = sqrt_c / sum; return pi; } int main() { const unsigned int precision = 100000; // 二进制精度位 const unsigned int iterations = 1000; // 迭代次数 std::cout << "开始计算π值 (Chudnovsky算法)..." << std::endl; std::cout << "精度: " << precision << "位 | 最大迭代: " << iterations << std::endl; // 启动资源监控线程 std::thread monitor_thread(monitor_resources); // 记录开始时间 auto start_time = std::chrono::high_resolution_clock::now(); // 计算π值 pi_value = chudnovsky_pi(precision, iterations); // 记录结束时间 auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time); // 停止监控线程 stop_monitor = true; monitor_thread.join(); // 输出最终结果 std::cout << "\n\n计算完成!" << std::endl; std::cout << "耗时: " << duration.count() / 1000.0 << " 秒" << std::endl; std::cout << "最终π值(前50位): " << std::setprecision(50) << pi_value << std::endl; return 0; } 此代码报错,修复错误 报错信息:default.cpp:6:10: fatal error: 'gmpxx.h' file not found #include <gmpxx.h> ^~~~~~~~~ 1 error generated. 输出完整代码
最新发布
07-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

何曾参静谧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值