C++用strtok两次拆分字符串无法输出全部分词如何解决?
问题根因
核心问题出在C标准库strtok函数的实现机制上:
strtok内部使用静态存储区保存上一次切割后剩余字符串的起始位置,全局共享这个状态,天生不支持嵌套调用- 内层调用
strtok(token, "|")时,会直接覆盖外层第一次strtok(value, "&")存在静态区的位置信息。等内层循环结束回到外层调用strtok(NULL, "&")时,函数已经找不到原字符串剩余的&分隔符位置,直接返回NULL,外层循环直接终止。
另外补充一个注意点:strtok会直接修改传入的原字符串,将匹配到的分隔符替换为\0,如果原字符串后续需要复用,要提前拷贝备份再传入切割。
修复方案
方案1:使用可重入版本的切割函数(C风格兼容)
POSIX标准提供strtok_r、Windows平台提供strtok_s,都是线程安全的可重入版本,多了第三个参数由用户自己传入指针保存切割状态,内外层切割使用独立的状态变量就不会互相干扰:
#include <iostream> #include <string.h> using namespace std; int main () { char value[] = "Hello | my | Name & is | Pratik & lets see"; char* outer_save = NULL; // 外层&切割的状态保存变量 char* token = strtok_r(value, "&", &outer_save); while (token != NULL) { cout << "\n token: " << token; char* inner_save = NULL; // 内层|切割的状态保存变量,和外层独立 char* token_1 = strtok_r(token, "|", &inner_save); while (token_1 != NULL) { cout << "\n token_1: " << token_1; token_1 = strtok_r(NULL, "|", &inner_save); } token = strtok_r(NULL, "&", &outer_save); } return 0; }
方案2:使用C++风格字符串切割(更安全无兼容问题)
直接用std::string实现自定义切割逻辑,没有静态状态冲突问题,也不会强制修改原字符串:
#include <iostream> #include <string> #include <vector> // 通用字符串切割函数 std::vector<std::string> split(const std::string& s, char delimiter) { std::vector<std::string> tokens; std::string temp; for (char c : s) { if (c == delimiter) { if (!temp.empty()) { tokens.push_back(temp); temp.clear(); } } else { temp += c; } } if (!temp.empty()) tokens.push_back(temp); return tokens; } int main() { std::string value = "Hello | my | Name & is | Pratik & lets see"; auto outer_tokens = split(value, '&'); for (const auto& outer_tok : outer_tokens) { std::cout << "\n token: " << outer_tok; auto inner_tokens = split(outer_tok, '|'); for (const auto& inner_tok : inner_tokens) { std::cout << "\n token_1: " << inner_tok; } } return 0; }
两种方案都可以完整输出所有分层分词结果。
内容的提问来源于stack exchange,提问作者Pratik
相关产品推荐
相关产品推荐

