1. 为什么我们需要一个通用的split模板函数
在C++标准库中,字符串分割是一个常见但未被直接支持的操作。每次需要分割字符串时,开发者往往需要重复编写类似的循环和条件判断代码。这种重复劳动不仅浪费时间,还容易引入错误。
我曾在多个项目中遇到过这样的场景:从CSV文件读取数据、解析日志条目、处理网络请求参数等,都需要对字符串进行分割。每次都要重新实现分割逻辑,既繁琐又容易出错。这就是为什么我们需要一个通用的、类型安全的split模板函数。
标准库中的std::string提供了find和substr等基础方法,但缺少直接的分割功能。第三方库如Boost虽然提供了解决方案,但引入整个Boost库可能过于重量级。自己实现一个轻量级的split模板,既能满足特定需求,又能保持代码简洁。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. split模板的设计思路
2.1 函数签名设计
一个好的split函数应该考虑以下要素:
- 支持多种分隔符(单个字符、字符串、谓词等)
- 处理空子串的选项
- 输出结果的容器类型
- 性能考量
基于这些考虑,我设计的函数签名如下:
cpp复制template<typename StringT, typename DelimiterT, typename ContainerT = std::vector<StringT>>
ContainerT split(const StringT& str, DelimiterT delimiter,
bool keep_empty = false, bool trim_whitespace = false);
2.2 模板参数解析
- StringT:不仅支持
std::string,也支持std::wstring等字符串类型 - DelimiterT:可以是字符、字符串或谓词函数,提供最大灵活性
- ContainerT:默认使用
std::vector,但允许用户指定其他容器
这种设计遵循了STL的通用性原则,与标准库中的算法设计理念一致。
3. 核心实现解析
3.1 基础分割算法
以下是支持字符分隔符的核心实现:
cpp复制template<typename StringT, typename DelimiterT, typename ContainerT>
ContainerT split_impl(const StringT& str, DelimiterT delimiter,
bool keep_empty, std::true_type /* is_char */) {
ContainerT result;
typename StringT::size_type pos = 0, last_pos = 0;
while ((pos = str.find(delimiter, last_pos)) != StringT::npos) {
if (pos > last_pos || keep_empty) {
auto token = str.substr(last_pos, pos - last_pos);
result.push_back(std::move(token));
}
last_pos = pos + 1;
}
// 添加最后一个token
if (last_pos < str.size() || keep_empty) {
result.push_back(str.substr(last_pos));
}
return result;
}
3.2 字符串分隔符支持
对于字符串分隔符,算法需要稍作调整:
cpp复制template<typename StringT, typename DelimiterT, typename ContainerT>
ContainerT split_impl(const StringT& str, DelimiterT delimiter,
bool keep_empty, std::false_type /* is_string */) {
ContainerT result;
typename StringT::size_type pos = 0, last_pos = 0;
const auto delim_size = delimiter.size();
while ((pos = str.find(delimiter, last_pos)) != StringT::npos) {
if (pos > last_pos || keep_empty) {
auto token = str.substr(last_pos, pos - last_pos);
result.push_back(std::move(token));
}
last_pos = pos + delim_size;
}
if (last_pos < str.size() || keep_empty) {
result.push_back(str.substr(last_pos));
}
return result;
}
3.3 类型分发与接口函数
通过类型特性分发到不同的实现:
cpp复制template<typename StringT, typename DelimiterT, typename ContainerT>
ContainerT split(const StringT& str, DelimiterT delimiter,
bool keep_empty = false) {
using is_char = std::integral_constant<bool,
std::is_same<DelimiterT, typename StringT::value_type>::value ||
std::is_convertible<DelimiterT, typename StringT::value_type>::value>;
return split_impl(str, delimiter, keep_empty, is_char{});
}
4. 高级功能实现
4.1 谓词支持
为了支持更复杂的分割逻辑,我们可以添加谓词支持:
cpp复制template<typename StringT, typename PredicateT, typename ContainerT>
ContainerT split_if(const StringT& str, PredicateT predicate,
bool keep_empty = false) {
ContainerT result;
typename StringT::size_type last_pos = 0;
for (typename StringT::size_type i = 0; i < str.size(); ++i) {
if (predicate(str[i])) {
if (i > last_pos || keep_empty) {
resul
