如何优化基于多分隔符的C++字符串分割函数性能?
优化按多分隔符分割字符串的C++实现
原代码的核心性能瓶颈
你的实现性能差主要源于几个关键问题:
- 频繁的临时字符串生成:每次调用
str.substr(i, delimeters[j].size())都会创建新的临时字符串,伴随内存分配和拷贝,长字符串场景下开销极大。 - 冗余的字符串替换操作:判断分隔符是否非全空格时调用的
replace函数,会完整复制分隔符并循环替换空格,属于完全不必要的性能浪费。 - 值传递参数:函数参数
str和delimeters用值传递,每次调用都会触发完整拷贝,大字符串或多分隔符场景下这部分开销非常可观。 - 低效的匹配逻辑:逐个字符遍历+逐个分隔符匹配,没有优先匹配长分隔符的逻辑,既容易出现误匹配,又增加了不必要的循环次数。
优化后的实现
下面是针对上述问题优化后的代码,性能提升显著:
#include <vector> #include <string> #include <algorithm> #include <cctype> // 判断字符串是否全为空格 bool is_all_space(const std::string& s) { for (unsigned char c : s) { if (!std::isspace(c)) { return false; } } return true; } std::vector<std::string> split_with_delimeter(const std::string& str, const std::vector<std::string>& delimeters) { std::vector<std::string> result; // 预分配空间,减少vector动态扩容的开销 result.reserve(str.size() / 8); std::string token; size_t pos = 0; const size_t str_len = str.size(); // 预处理分隔符:按长度从长到短排序,优先匹配长分隔符,避免误匹配 std::vector<std::string> sorted_delims = delimeters; std::sort(sorted_delims.begin(), sorted_delims.end(), [](const std::string& a, const std::string& b) { return a.size() > b.size(); }); while (pos < str_len) { bool found_delim = false; for (const auto& delim : sorted_delims) { const size_t delim_len = delim.size(); // 剩余长度不足,直接跳过当前分隔符 if (pos + delim_len > str_len) { continue; } // 直接对比字符,避免生成临时子串 bool match = true; for (size_t k = 0; k < delim_len; ++k) { if (str[pos + k] != delim[k]) { match = false; break; } } if (match) { // 加入之前的有效token(非空) if (!token.empty()) { result.push_back(std::move(token)); // 移动语义,避免字符串拷贝 token.clear(); } // 非全空格的分隔符才加入结果 if (!is_all_space(delim)) { result.push_back(delim); } pos += delim_len; found_delim = true; break; } } if (!found_delim) { token += str[pos]; ++pos; } } // 处理最后剩余的token if (!token.empty()) { result.push_back(std::move(token)); } return result; }
关键优化点说明
- const引用传递参数:避免了原代码中参数拷贝的开销,直接使用传入的原对象。
- 分隔符排序预处理:按长度降序排列分隔符,优先匹配长分隔符,既避免了短分隔符先匹配导致的错误(比如同时有"ab"和"a"时,先匹配"ab"),又减少了匹配次数。
- 直接字符匹配:代替
substr生成临时字符串,直接对比原字符串的字符,彻底消除了临时字符串的内存分配和拷贝开销,这是性能提升的核心。 - 替换冗余的replace函数:用
is_all_space直接遍历字符判断分隔符是否全为空格,没有任何多余的字符串操作。 - 移动语义:使用
std::move(token)将token的内容转移到vector中,避免了字符串拷贝,进一步降低开销。 - 预分配容器空间:通过
reserve提前为结果vector分配足够的空间,减少动态扩容时的内存重新分配和元素拷贝。
额外优化建议
- 如果你的分隔符都是单字符,可以进一步优化:把单字符分隔符存入
std::unordered_set<char>,直接O(1)判断当前字符是否为分隔符,性能会更上一层楼。 - 若使用C++17及以上版本,可以用
std::string_view代替std::string传递参数和存储结果,彻底避免不必要的字符串拷贝。
内容的提问来源于stack exchange,提问作者Cheese Danish
相关产品推荐
相关产品推荐

