下面的代码来自对 this question on string splitting 的回答.它使用指针,对该答案的评论表明它可以适用于 std::string
。如何使用 std::string
的特性来实现相同的算法,例如使用迭代器?
#include <vector>
#include <string>
using namespace std;
vector<string> split(const char *str, char c = ',')
{
vector<string> result;
do
{
const char *begin = str;
while(*str != c && *str)
str++;
result.push_back(string(begin, str));
} while (0 != *str++);
return result;
}
好吧,我显然用字符串替换了 char,但后来我注意到他使用了指向字符开头的指针。字符串甚至可能吗?循环终止标准如何变化?进行此更改时还有什么我需要担心的吗?
最佳答案
您可以使用 iterators而不是指针。迭代器提供了一种遍历容器的方法,通常可以将其视为类似于指针。
在这种情况下,您可以使用的
对象获取引用第一个字符的迭代器,begin()
成员函数(如果不需要修改元素,则可以使用cbegin()
) >std::stringend()
(或cend()
)成员函数获取一个“最后一个”的迭代器。
对于内循环,你的终止条件是一样的;当您点击要拆分字符串的分隔符时,您想停止。对于外部循环,您可以将迭代器与您已经从 end()
成员函数中获得的结束迭代器进行比较,而不是将字符值与 '\0'
进行比较.算法的其余部分非常相似;迭代器在取消引用和递增方面像指针一样工作:
std::vector<std::string> split(const std::string& str, const char delim = ',') {
std::vector<std::string> result;
auto end = str.cend();
auto iter = str.cbegin();
while (iter != end) {
auto begin = iter;
while (iter != end && *iter != delim) ++iter;
result.push_back(std::string(begin, iter));
if (iter != end) ++iter; // See note (**) below.
}
return result;
}
请注意内部循环条件中的细微差别:它现在测试我们是否在尝试解除引用之前到达结尾。这是因为我们不能取消引用指向容器末尾的迭代器,所以我们必须在尝试取消引用之前检查这一点。原始算法假定空字符结束字符串,因此我们可以取消引用指向该位置的指针。
(**) 当iter
已经是end
时,iter++ != end
的有效性正在讨论中在 Are end+1 iterators for std::string allowed?
我已将此 if
语句添加到原始算法中,以在 iter
到达内部循环中的 end
时中断循环。这避免了向已经是 end
迭代器的迭代器添加 1,并避免了潜在的问题。
关于c++ - 如何使用指针调整字符串拆分算法,使其改用迭代器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33629158/