【C++】 分割字符串方法汇总

C++ 分割字符串方法汇总

引言

557. 反转字符串中的单词 III - 力扣(LeetCode)

本文是我在遇到这个题目时脑子里第一时间蹦出如何能够像Python那样优雅的分割而产生的。

做完看题解后才发现我把简单问题想复杂了……但也不失为一种解决方案,于是再此记录一下。

方法一:使用C风格字符串函数

C语言中提供了strtokstrtok_r函数用于字符串分割。strtok函数用于分割字符串,但存在线程安全问题,而strtok_r是线程安全的版本。

使用示例(strtok_r为例)

strtok_r函数原型char *strtok_r(char *str, const char *del, char **saveptr);

  • str :指向待分割的指针,第一次调用strtok_r时,应该传入待分割字符串,在后续调用中,如果继续分割同一个字符串,str应该设置为NULL
  • del:包含一个或多个分隔符的字符串。strtok_r将使用这个字符串中的任何一个字符作为分隔符来分割原始字符串。
  • saveptr:指向char *类型的指针的指针。strtok_r函数使用save_ptr来保存它内部的状态信息,这样在后续的调用中可以继续从上次停止的地方开始分割。在第一次调用strtok_r时,save_ptr的值可以是任意值,因为它会被strtok_r初始化。在后续调用中,save_ptr应该保持不变,以便strtok_r可以正确地恢复分割的位置。
#include <cstring>   // 包含必要的头文件
#include <iostream>
#include <vector>
using namespace std;

// 定义函数用于使用C风格函数分割字符串
vector<string> split_c_style(const char* str, char delimiter) {
    vector<string> result; // 创建结果向量
    char* token;           // 用于保存分割得到的子串
    char* rest = strdup(str); // 使用strdup复制字符串,避免修改原字符串

    // 使用strtok_r分割字符串,保存中间状态
    token = strtok_r(rest, &delimiter, &rest);
    while (token != nullptr) {
        result.push_back(token); // 将分割得到的子串添加到结果向量
        token = strtok_r(nullptr, &delimiter, &rest); // 继续分割剩余的字符串
    }

    // 释放strdup分配的内存
    free(rest);
    return result;
}

注意事项

  • strtokstrtok_r会修改原始字符串,因此通常需要先复制字符串。
  • 使用strtok_r时,需要管理额外的char*指针来保存中间状态。

方法二:使用istringstream

istringstream是C++标准库中的流类,可以用于解析字符串,类似于从文件中读取数据。

使用示例

#include <sstream> // 包含必要的头文件
#include <vector>
#include <string>
using namespace std;

// 定义函数使用istringstream分割字符串
vector<string> split_with_istringstream(const string& str, char delimiter) {
    vector<string> result; // 创建结果向量
    istringstream iss(str); // 创建istringstream对象
    string token;
    
    // 使用getline读取子串,直到遇到分隔符
    while (getline(iss, token, delimiter)) {
        result.push_back(token); // 将子串添加到结果向量
    }
    return result;
}

优点

  • 更加面向对象,代码结构清晰。
  • 不会修改原始字符串。

方法三:使用regex

regex库提供了强大的正则表达式支持,可以用于复杂的字符串分割。

使用示例

#include <regex> // 包含必要的头文件
#include <vector>
#include <string>
using namespace std;

// 定义函数使用regex分割字符串
vector<string> split_with_regex(const string& str, const string& pattern) {
    vector<string> result; // 创建结果向量
    regex re(pattern);     // 创建regex对象
    sregex_token_iterator it(str.begin(), str.end(), re, -1); // 创建迭代器
    sregex_token_iterator reg_end; // 结束迭代器
    
    // 遍历迭代器,将子串添加到结果向量
    for (; it != reg_end; ++it) {
        result.push_back(*it);
    }
    return result;
}

优点

  • 可以处理更复杂的分割模式,如忽略连续的分隔符。
  • 提供了强大的正则表达式功能。

方法四:手动实现分割

对于简单的需求,手动实现字符串分割函数也是一个不错的选择,可以完全控制分割逻辑。

使用示例

#include <vector>
#include <string>
using namespace std;

// 定义函数手动分割字符串
vector<string> manual_split(const string& str, char delimiter) {
    vector<string> result; // 创建结果向量
    size_t start = 0;      // 开始位置
    size_t end = str.find(delimiter); // 结束位置
    
    // 循环查找分隔符,直到遍历完整个字符串
    while (end != string::npos) {
        result.push_back(str.substr(start, end - start)); // 将子串添加到结果向量
        start = end + 1; // 更新开始位置
        end = str.find(delimiter, start); // 查找下一个分隔符的位置
    }
    
    // 添加最后一个子串到结果向量
    result.push_back(str.substr(start));
    return result;
}

优点

  • 完全控制逻辑,适用于特定需求。
  • 不依赖额外的库函数。

总结

以上四种方法各有优缺点,选择哪一种取决于具体的应用场景和需求。对于简单的字符串分割,使用istringstream或手动实现分割函数可能更为合适。对于复杂的分割需求,regex提供了强大的功能。而在处理C风格字符串或需要线程安全的场景下,strtok_r可以作为一个备选方案。

  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值