问题 迭代字符串单词的最优雅方式[关闭]
迭代字符串的最优雅的方法是什么?可以假设该字符串由用空格分隔的单词组成。
请注意,我对C字符串函数或那种字符操作/访问不感兴趣。另外,请在答案中优先考虑优雅而不是效率。
我现在最好的解决方案是:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main()
{
string s = "Somewhere down the road";
istringstream iss(s);
do
{
string subs;
iss >> subs;
cout << "Substring: " << subs << endl;
} while (iss);
}
12453
2019-05-20 20:51:17
起源
答案:
对于它的价值,这是从输入字符串中提取标记的另一种方法,仅依赖于标准库设施。这是STL设计背后的力量和优雅的一个例子。
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
int main() {
using namespace std;
string sentence = "And I feel fine...";
istringstream iss(sentence);
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
ostream_iterator<string>(cout, "\n"));
}
可以使用相同的泛型将它们插入到容器中,而不是将提取的标记复制到输出流 copy
算法。
vector<string> tokens;
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter(tokens));
...或创建 vector
直:
vector<string> tokens{istream_iterator<string>{iss},
istream_iterator<string>{}};
1189
我用它来分隔字符串。第一个将结果放在预先构造的向量中,第二个返回一个新向量。
#include <string>
#include <sstream>
#include <vector>
#include <iterator>
template<typename Out>
void split(const std::string &s, char delim, Out result) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
*(result++) = item;
}
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
split(s, delim, std::back_inserter(elems));
return elems;
}
请注意,此解决方案不会跳过空标记,因此以下内容将找到4个项目,其中一个项目为空:
std::vector<std::string> x = split("one:two::three", ':');
2308
使用Boost的可能解决方案可能是:
#include <boost/algorithm/string.hpp>
std::vector<std::string> strs;
boost::split(strs, "string to split", boost::is_any_of("\t "));
这种方法可能比这更快 stringstream
做法。由于这是一个通用模板函数,因此可以使用各种分隔符来分割其他类型的字符串(wchar等或UTF-8)。
见 文件 详情。
794
#include <vector>
#include <string>
#include <sstream>
int main()
{
std::string str("Split me by whitespaces");
std::string buf; // Have a buffer string
std::stringstream ss(str); // Insert the string into a stream
std::vector<std::string> tokens; // Create vector to hold our words
while (ss >> buf)
tokens.push_back(buf);
return 0;
}
321
对于那些不能很好地牺牲代码大小的所有效率并将“高效”视为一种优雅的人来说,下面的内容应该是一个最佳点(我认为模板容器类是一个非常优雅的添加。):
template < class ContainerT >
void tokenize(const std::string& str, ContainerT& tokens,
const std::string& delimiters = " ", bool trimEmpty = false)
{
std::string::size_type pos, lastPos = 0, length = str.length();
using value_type = typename ContainerT::value_type;
using size_type = typename ContainerT::size_type;
while(lastPos < length + 1)
{
pos = str.find_first_of(delimiters, lastPos);
if(pos == std::string::npos)
{
pos = length;
}
if(pos != lastPos || !trimEmpty)
tokens.push_back(value_type(str.data()+lastPos,
(size_type)pos-lastPos ));
lastPos = pos + 1;
}
}
我通常选择使用 std::vector<std::string>
类型作为我的第二个参数(ContainerT
)...但是 list<>
比...更快 vector<>
因为当不需要直接访问时,您甚至可以创建自己的字符串类并使用类似的东西 std::list<subString>
哪里 subString
因为速度提升令人难以置信,所以没有任何副本。
它比本页面上最快的标记化速度快一倍以上,几乎是其他标记的5倍。此外,使用完美的参数类型,您可以消除所有字符串和列表副本,以提高速度。
此外,它不会(非常低效)返回结果,而是将标记作为参考传递,因此如果您愿意,还可以使用多个调用来构建标记。
最后,它允许您指定是否通过最后一个可选参数从结果中修剪空标记。
它所需要的只是 std::string
......其余的都是可选的。它不使用流或boost库,但足够灵活,能够自然地接受这些外来类型中的一些。
168
这是另一种解决方案。它结构紧凑,效率高:
std::vector<std::string> split(const std::string &text, char sep) {
std::vector<std::string> tokens;
std::size_t start = 0, end = 0;
while ((end = text.find(sep, start)) != std::string::npos) {
tokens.push_back(text.substr(start, end - start));
start = end + 1;
}
tokens.push_back(text.substr(start));
return tokens;
}
它可以很容易地进行处理,以处理字符串分隔符,宽字符串等。
请注意分裂 ""
导致单个空字符串和拆分 ","
(即sep)导致两个空字符串。
它也可以轻松扩展为跳过空标记:
std::vector<std::string> split(const std::string &text, char sep) {
std::vector<std::string> tokens;
std::size_t start = 0, end = 0;
while ((end = text.find(sep, start)) != std::string::npos) {
if (end != start) {
tokens.push_back(text.substr(start, end - start));
}
start = end + 1;
}
if (end != start) {
tokens.push_back(text.substr(start));
}
return tokens;
}
如果需要在跳过空标记的情况下将字符串拆分为多个分隔符,则可以使用以下版本:
std::vector<std::string> split(const std::string& text, const std::string& delims)
{
std::vector<std::string> tokens;
std::size_t start = text.find_first_not_of(delims), end = 0;
while((end = text.find_first_of(delims, start)) != std::string::npos)
{
tokens.push_back(text.substr(start, end - start));
start = text.find_first_not_of(delims, end);
}
if(start != std::string::npos)
tokens.push_back(text.substr(start));
return tokens;
}
150
这是我最喜欢的迭代字符串的方法。你可以随心所欲地做任何事。
string line = "a line of text to iterate through";
string word;
istringstream iss(line, istringstream::in);
while( iss >> word )
{
// Do something on `word` here...
}
106