C++ std_stringstream

C++ std::stringstream

std::stringstream 是 C++ 标准库中一个强大的字符串流类,它允许像使用输入输出流一样操作字符串,提供了丰富的格式化和数据处理功能。

基本概念和头文件

cpp 复制代码
#include <sstream>  // 主要头文件
#include <iostream>
#include <string>

// 三种字符串流类型:
std::stringstream ss;  // 输入输出字符串流
std::istringstream iss; // 只输入字符串流  
std::ostringstream oss; // 只输出字符串流

基本用法

1. 创建和基本操作

cpp 复制代码
#include <sstream>
#include <iostream>

void basic_usage() {
    // 创建字符串流
    std::stringstream ss;
    
    // 写入数据
    ss << "Hello, ";
    ss << "World! ";
    ss << 42 << " ";
    ss << 3.14;
    
    // 获取字符串
    std::string result = ss.str();
    std::cout << "内容: " << result << std::endl;
    // 输出: 内容: Hello, World! 42 3.14
    
    // 清空流
    ss.str("");  // 清空内容
    ss.clear();  // 清除错误状态
}

2. 数据提取

cpp 复制代码
#include <sstream>
#include <string>

void extraction_example() {
    std::string data = "John 25 75000.50";
    std::stringstream ss(data);
    
    std::string name;
    int age;
    double salary;
    
    // 从流中提取数据
    ss >> name >> age >> salary;
    
    std::cout << "姓名: " << name << std::endl;
    std::cout << "年龄: " << age << std::endl;
    std::cout << "薪资: " << salary << std::endl;
}

字符串流类型详解

1. std::ostringstream - 输出字符串流

cpp 复制代码
#include <sstream>
#include <iostream>

void ostringstream_example() {
    std::ostringstream oss;
    
    // 只能输出,不能输入
    oss << "计算结果: " << (10 + 20) << std::endl;
    oss << "圆周率: " << 3.14159 << std::endl;
    oss << "布尔值: " << std::boolalpha << true;
    
    std::string output = oss.str();
    std::cout << "输出内容:\n" << output << std::endl;
    
    // 获取流状态
    std::cout << "是否良好: " << oss.good() << std::endl;
    std::cout << "是否结束: " << oss.eof() << std::endl;
}

2. std::istringstream - 输入字符串流

cpp 复制代码
#include <sstream>
#include <vector>

void istringstream_example() {
    std::string csv_data = "apple,banana,cherry,date,elderberry";
    std::istringstream iss(csv_data);
    
    std::vector<std::string> fruits;
    std::string fruit;
    
    // 使用逗号分隔符读取
    while (std::getline(iss, fruit, ',')) {
        fruits.push_back(fruit);
    }
    
    std::cout << "水果列表:" << std::endl;
    for (const auto& f : fruits) {
        std::cout << "- " << f << std::endl;
    }
    
    // 检查流状态
    if (iss.eof()) {
        std::cout << "已到达流末尾" << std::endl;
    }
}

3. std::stringstream - 双向字符串流

cpp 复制代码
#include <sstream>
#include <iomanip>

void stringstream_bidirectional() {
    std::stringstream ss;
    
    // 写入数据
    ss << "产品A: " << std::fixed << std::setprecision(2) << 19.99;
    ss << " | 产品B: " << 29.50;
    
    // 读取数据
    std::string product1, product2;
    double price1, price2;
    char separator;
    
    ss >> product1 >> separator >> price1;
    ss.ignore(10, '|');  // 跳过分隔符
    ss >> product2 >> separator >> price2;
    
    std::cout << product1 << ": $" << price1 << std::endl;
    std::cout << product2 << ": $" << price2 << std::endl;
}

高级功能和应用

1. 类型转换工具

cpp 复制代码
#include <sstream>
#include <string>
#include <stdexcept>

class StringConverter {
public:
    // 任意类型转换为字符串
    template<typename T>
    static std::string toString(const T& value) {
        std::ostringstream oss;
        oss << value;
        if (!oss) {
            throw std::runtime_error("转换失败");
        }
        return oss.str();
    }
    
    // 字符串转换为任意类型
    template<typename T>
    static T fromString(const std::string& str) {
        std::istringstream iss(str);
        T value;
        iss >> value;
        if (!iss) {
            throw std::runtime_error("转换失败: " + str);
        }
        return value;
    }
    
    // 检查是否可以转换
    template<typename T>
    static bool canConvert(const std::string& str) {
        std::istringstream iss(str);
        T value;
        return (iss >> value) && iss.eof();
    }
};

// 使用示例
void conversion_example() {
    try {
        // 转换为字符串
        std::string str_num = StringConverter::toString(42);
        std::string str_double = StringConverter::toString(3.14159);
        
        // 从字符串转换
        int num = StringConverter::fromString<int>("123");
        double pi = StringConverter::fromString<double>("3.14");
        
        // 检查转换
        bool can_convert = StringConverter::canConvert<int>("456");
        
        std::cout << "字符串数字: " << str_num << std::endl;
        std::cout << "转换回整数: " << num << std::endl;
        std::cout << "能否转换 'abc': " 
                  << StringConverter::canConvert<int>("abc") << std::endl;
                  
    } catch (const std::exception& e) {
        std::cerr << "错误: " << e.what() << std::endl;
    }
}

2. 字符串格式化

cpp 复制代码
#include <sstream>
#include <iomanip>

void formatting_example() {
    std::ostringstream oss;
    
    // 数字格式化
    oss << "十进制: " << 42 << std::endl;
    oss << "十六进制: " << std::hex << 42 << std::endl;
    oss << "八进制: " << std::oct << 42 << std::endl;
    
    // 浮点数格式化
    oss << std::dec << std::fixed << std::setprecision(3);
    oss << "固定小数: " << 3.14159 << std::endl;
    
    oss << std::scientific;
    oss << "科学计数: " << 3.14159 << std::endl;
    
    // 对齐和填充
    oss << std::left << std::setw(10) << "左对齐" << "|" << std::endl;
    oss << std::right << std::setw(10) << "右对齐" << "|" << std::endl;
    oss << std::setfill('*') << std::setw(10) << "填充" << std::endl;
    
    std::cout << oss.str() << std::endl;
}

3. 复杂数据序列化

cpp 复制代码
#include <sstream>
#include <vector>
#include <map>

class DataSerializer {
public:
    // 序列化 vector 到字符串
    template<typename T>
    static std::string serializeVector(const std::vector<T>& vec, 
                                     const std::string& delimiter = ",") {
        std::ostringstream oss;
        for (size_t i = 0; i < vec.size(); ++i) {
            if (i > 0) oss << delimiter;
            oss << vec[i];
        }
        return oss.str();
    }
    
    // 从字符串反序列化到 vector
    template<typename T>
    static std::vector<T> deserializeVector(const std::string& str,
                                          const std::string& delimiter = ",") {
        std::vector<T> result;
        std::istringstream iss(str);
        std::string token;
        
        while (std::getline(iss, token, delimiter[0])) {
            std::istringstream token_stream(token);
            T value;
            if (token_stream >> value) {
                result.push_back(value);
            }
        }
        return result;
    }
    
    // 序列化 map 到字符串
    template<typename K, typename V>
    static std::string serializeMap(const std::map<K, V>& map,
                                  const std::string& pair_sep = "=",
                                  const std::string& entry_sep = ";") {
        std::ostringstream oss;
        bool first = true;
        for (const auto& [key, value] : map) {
            if (!first) oss << entry_sep;
            oss << key << pair_sep << value;
            first = false;
        }
        return oss.str();
    }
};

void serialization_example() {
    // 序列化 vector
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    std::string serialized = DataSerializer::serializeVector(numbers);
    std::cout << "序列化: " << serialized << std::endl;
    
    // 反序列化
    auto deserialized = DataSerializer::deserializeVector<int>(serialized);
    std::cout << "反序列化: ";
    for (int num : deserialized) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    
    // 序列化 map
    std::map<std::string, int> scores = {{"Alice", 95}, {"Bob", 87}, {"Charlie", 92}};
    std::string map_str = DataSerializer::serializeMap(scores);
    std::cout << "Map 序列化: " << map_str << std::endl;
}

实际应用场景

1. 日志系统

cpp 复制代码
#include <sstream>
#include <chrono>
#include <iomanip>

class Logger {
private:
    std::ostringstream& getStream() {
        static thread_local std::ostringstream oss;
        oss.str("");  // 清空内容
        oss.clear();  // 清除状态
        
        // 添加时间戳
        auto now = std::chrono::system_clock::now();
        auto time_t = std::chrono::system_clock::to_time_t(now);
        oss << "[" << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S") << "] ";
        
        return oss;
    }
    
public:
    void log(const std::string& message) {
        auto& oss = getStream();
        oss << "[INFO] " << message;
        std::cout << oss.str() << std::endl;
    }
    
    void error(const std::string& message) {
        auto& oss = getStream();
        oss << "[ERROR] " << message;
        std::cerr << oss.str() << std::endl;
    }
    
    template<typename... Args>
    void logFormatted(const std::string& format, Args... args) {
        auto& oss = getStream();
        oss << "[INFO] ";
        formatMessage(oss, format, args...);
        std::cout << oss.str() << std::endl;
    }
    
private:
    // 递归终止
    void formatMessage(std::ostringstream& oss, const std::string& format) {
        oss << format;
    }
    
    // 递归展开参数包
    template<typename T, typename... Args>
    void formatMessage(std::ostringstream& oss, const std::string& format, 
                      T value, Args... args) {
        size_t pos = format.find("{}");
        if (pos != std::string::npos) {
            oss << format.substr(0, pos);
            oss << value;
            formatMessage(oss, format.substr(pos + 2), args...);
        } else {
            oss << format;
        }
    }
};

void logger_example() {
    Logger logger;
    logger.log("应用程序启动");
    logger.error("发生了一个错误");
    logger.logFormatted("用户 {} 在 {} 执行了操作", "Alice", "登录");
}

2. SQL 查询构建器

cpp 复制代码
#include <sstream>
#include <vector>

class QueryBuilder {
private:
    std::ostringstream query_;
    
public:
    QueryBuilder& select(const std::vector<std::string>& columns = {"*"}) {
        query_ << "SELECT ";
        for (size_t i = 0; i < columns.size(); ++i) {
            if (i > 0) query_ << ", ";
            query_ << columns[i];
        }
        return *this;
    }
    
    QueryBuilder& from(const std::string& table) {
        query_ << " FROM " << table;
        return *this;
    }
    
    QueryBuilder& where(const std::string& condition) {
        query_ << " WHERE " << condition;
        return *this;
    }
    
    QueryBuilder& andWhere(const std::string& condition) {
        query_ << " AND " << condition;
        return *this;
    }
    
    QueryBuilder& orWhere(const std::string& condition) {
        query_ << " OR " << condition;
        return *this;
    }
    
    QueryBuilder& orderBy(const std::string& column, bool ascending = true) {
        query_ << " ORDER BY " << column << (ascending ? " ASC" : " DESC");
        return *this;
    }
    
    QueryBuilder& limit(int count) {
        query_ << " LIMIT " << count;
        return *this;
    }
    
    std::string build() {
        return query_.str();
    }
    
    void reset() {
        query_.str("");
        query_.clear();
    }
};

void query_builder_example() {
    QueryBuilder qb;
    
    std::string query = qb.select({"id", "name", "email"})
                         .from("users")
                         .where("age > 18")
                         .andWhere("status = 'active'")
                         .orderBy("name")
                         .limit(10)
                         .build();
    
    std::cout << "生成的 SQL: " << query << std::endl;
    // 输出: SELECT id, name, email FROM users WHERE age > 18 AND status = 'active' ORDER BY name ASC LIMIT 10
}

3. 配置解析器

cpp 复制代码
#include <sstream>
#include <map>
#include <algorithm>

class ConfigParser {
private:
    std::map<std::string, std::string> config_;
    
public:
    bool parse(const std::string& config_text) {
        std::istringstream iss(config_text);
        std::string line;
        int line_num = 0;
        
        while (std::getline(iss, line)) {
            ++line_num;
            
            // 移除前后空白
            line.erase(0, line.find_first_not_of(" \t"));
            line.erase(line.find_last_not_of(" \t") + 1);
            
            // 跳过空行和注释
            if (line.empty() || line[0] == '#') {
                continue;
            }
            
            // 解析键值对
            std::istringstream line_stream(line);
            std::string key, value;
            
            if (std::getline(line_stream, key, '=')) {
                if (std::getline(line_stream, value)) {
                    // 移除值的空白
                    value.erase(0, value.find_first_not_of(" \t"));
                    value.erase(value.find_last_not_of(" \t") + 1);
                    
                    config_[key] = value;
                } else {
                    std::cerr << "配置错误第 " << line_num << " 行: 缺少值" << std::endl;
                    return false;
                }
            }
        }
        return true;
    }
    
    template<typename T>
    T get(const std::string& key, const T& defaultValue = T()) const {
        auto it = config_.find(key);
        if (it != config_.end()) {
            std::istringstream iss(it->second);
            T value;
            if (iss >> value) {
                return value;
            }
        }
        return defaultValue;
    }
    
    std::string getString(const std::string& key, const std::string& defaultValue = "") const {
        auto it = config_.find(key);
        return it != config_.end() ? it->second : defaultValue;
    }
};

void config_parser_example() {
    std::string config_text = R"(
        # 数据库配置
        db.host = localhost
        db.port = 3306
        db.name = myapp
        
        # 应用配置
        app.name = MyApplication
        app.debug = true
        app.max_connections = 100
    )";
    
    ConfigParser parser;
    if (parser.parse(config_text)) {
        std::cout << "数据库主机: " << parser.getString("db.host") << std::endl;
        std::cout << "数据库端口: " << parser.get<int>("db.port") << std::endl;
        std::cout << "调试模式: " << std::boolalpha << parser.get<bool>("app.debug") << std::endl;
    }
}

性能优化和最佳实践

1. 重用 stringstream 对象

cpp 复制代码
#include <sstream>

class StringStreamPool {
private:
    static thread_local std::stringstream ss;
    
public:
    static std::stringstream& get() {
        ss.str("");   // 清空内容
        ss.clear();   // 清除状态标志
        return ss;
    }
    
    template<typename T>
    static std::string toString(const T& value) {
        auto& stream = get();
        stream << value;
        return stream.str();
    }
};

void performance_example() {
    // 避免重复创建 stringstream
    for (int i = 0; i < 1000; ++i) {
        // 不好的做法:每次创建新的 stringstream
        // std::stringstream ss;
        // ss << i;
        // std::string str = ss.str();
        
        // 好的做法:重用 stringstream
        std::string str = StringStreamPool::toString(i);
    }
}

2. 错误处理

cpp 复制代码
#include <sstream>
#include <stdexcept>

void robust_stringstream_usage() {
    std::stringstream ss;
    
    try {
        // 写入操作
        ss << "一些数据";
        if (ss.fail()) {
            throw std::runtime_error("写入 stringstream 失败");
        }
        
        // 读取操作
        int value;
        ss >> value;
        if (ss.fail()) {
            throw std::runtime_error("从 stringstream 读取失败");
        }
        
        // 检查是否完全消费了输入
        std::string remaining;
        if (ss >> remaining) {
            throw std::runtime_error("输入数据有剩余: " + remaining);
        }
        
    } catch (const std::exception& e) {
        std::cerr << "错误: " << e.what() << std::endl;
        // 恢复流状态
        ss.clear();
        ss.str("");
    }
}

总结

std::stringstream 的主要优势:

  • 强大的字符串格式化能力
  • 类型安全的字符串转换
  • 灵活的数据序列化/反序列化
  • 与标准流一致的接口

常用场景:

  • 字符串构建和格式化
  • 类型转换(字符串 ↔ 其他类型)
  • 数据序列化
  • 文本解析
  • 日志记录
  • SQL 查询构建

最佳实践:

  1. 重用 stringstream 对象以提高性能
  2. 及时清理内容和状态(str("") 和 clear())
  3. 检查流操作是否成功
  4. 对于简单字符串拼接,考虑使用 std::string 的 += 操作
  5. 使用合适的字符串流类型(istringstream/ostringstream)

性能考虑:

  • 在性能关键路径中避免频繁创建 stringstream
  • 对于简单操作,直接使用字符串操作可能更快
  • 考虑预分配缓冲区大小(C++20 的 std::ostringstream::str() 可以保留容量)

std::stringstream 是 C++ 中处理字符串格式化和转换的强大工具,正确使用可以大大提高代码的可读性和维护性。

相关推荐
Mr.Winter`1 小时前
基于Proto3和单例模式的系统参数配置模块设计(附C++案例实现)
c++·人工智能·单例模式·机器人
v***87041 小时前
QoS质量配置
开发语言·智能路由器·php
Wpa.wk1 小时前
自动化测试环境配置-java+python
java·开发语言·python·测试工具·自动化
道一232 小时前
C#获取操作系统版本号方法
开发语言·c#
道一232 小时前
C# 判断文件是否存在的方法
开发语言·c#
信仰_2739932432 小时前
Java面试题
java·开发语言
CoovallyAIHub2 小时前
超越YOLOv8/v11!自研RKM-YOLO为输电线路巡检精度、速度双提升
深度学习·算法·计算机视觉
哭泣方源炼蛊2 小时前
HAUE 新生周赛(七)题解
数据结构·c++·算法
闫有尽意无琼2 小时前
银河麒麟v11 arm编译Qt creator8.0.2报错
开发语言·qt