还有另一种方式——连续传递方式、零分配、基于函数的分隔。
void split( auto&& data, auto&& splitter, auto&& operation ) {
using std::begin; using std::end;
auto prev = begin(data);
while (prev != end(data) ) {
auto&&[prev,next] = splitter( prev, end(data) );
operation(prev,next);
prev = next;
}
}
现在我们可以基于此编写特定的拆分函数。
auto anyOfSplitter(auto delimiters) {
return [delimiters](auto begin, auto end) {
while( begin != end && 0 == std::string_view(begin, end).find_first_of(delimiters) ) {
++begin;
}
auto view = std::string_view(begin, end);
auto next = view.find_first_of(delimiters);
if (next != view.npos)
return std::make_pair( begin, begin + next );
else
return std::make_pair( begin, end );
};
}
我们现在可以生成一个传统的std字符串分割,如下所示:
template<class C>
auto traditional_any_of_split( std::string_view<C> str, std::string_view<C> delim ) {
std::vector<std::basic_string<C>> retval;
split( str, anyOfSplitter(delim), [&](auto s, auto f) {
retval.emplace_back(s,f);
});
return retval;
}
或者我们可以改用find
auto findSplitter(auto delimiter) {
return [delimiter](auto begin, auto end) {
while( begin != end && 0 == std::string_view(begin, end).find(delimiter) ) {
begin += delimiter.size();
}
auto view = std::string_view(begin, end);
auto next = view.find(delimiter);
if (next != view.npos)
return std::make_pair( begin, begin + next );
else
return std::make_pair( begin, end );
};
}
template<class C>
auto traditional_find_split( std::string_view<C> str, std::string_view<C> delim ) {
std::vector<std::basic_string<C>> retval;
split( str, findSplitter(delim), [&](auto s, auto f) {
retval.emplace_back(s,f);
});
return retval;
}
通过更换分流器部分。
这两者都分配了一个返回值缓冲区。我们可以以手动管理生命周期为代价将返回值交换到字符串视图。
我们还可以采用一个延续,一次传递一个字符串视图,甚至避免分配视图向量。
这可以通过一个中止选项进行扩展,这样我们可以在读取几个前缀字符串后中止。