如何迭代由空格分隔的单词组成的字符串中的单词?
注意,我对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);
}
使用std::string_view和Eric Niebler的range-v3库:
https://wandbox.org/permlink/kW5lwRCL1pxjp2pW
#include <iostream>
#include <string>
#include <string_view>
#include "range/v3/view.hpp"
#include "range/v3/algorithm.hpp"
int main() {
std::string s = "Somewhere down the range v3 library";
ranges::for_each(s
| ranges::view::split(' ')
| ranges::view::transform([](auto &&sub) {
return std::string_view(&*sub.begin(), ranges::distance(sub));
}),
[](auto s) {std::cout << "Substring: " << s << "\n";}
);
}
通过使用循环的范围而不是范围::for_each算法:
#include <iostream>
#include <string>
#include <string_view>
#include "range/v3/view.hpp"
int main()
{
std::string str = "Somewhere down the range v3 library";
for (auto s : str | ranges::view::split(' ')
| ranges::view::transform([](auto&& sub) { return std::string_view(&*sub.begin(), ranges::distance(sub)); }
))
{
std::cout << "Substring: " << s << "\n";
}
}
我使用这个simpleton是因为我们得到了字符串类“特殊”(即非标准):
void splitString(const String &s, const String &delim, std::vector<String> &result) {
const int l = delim.length();
int f = 0;
int i = s.indexOf(delim,f);
while (i>=0) {
String token( i-f > 0 ? s.substring(f,i-f) : "");
result.push_back(token);
f=i+l;
i = s.indexOf(delim,f);
}
String token = s.substring(f);
result.push_back(token);
}
STL还没有这样的方法。
但是,您可以通过使用std::string::C_str()成员来使用C的strtok()函数,也可以编写自己的函数。下面是我在快速谷歌搜索(“STL字符串分割”)后找到的代码示例:
void Tokenize(const string& str,
vector<string>& tokens,
const string& delimiters = " ")
{
// Skip delimiters at beginning.
string::size_type lastPos = str.find_first_not_of(delimiters, 0);
// Find first "non-delimiter".
string::size_type pos = str.find_first_of(delimiters, lastPos);
while (string::npos != pos || string::npos != lastPos)
{
// Found a token, add it to the vector.
tokens.push_back(str.substr(lastPos, pos - lastPos));
// Skip delimiters. Note the "not_of"
lastPos = str.find_first_not_of(delimiters, pos);
// Find next "non-delimiter"
pos = str.find_first_of(delimiters, lastPos);
}
}
摘自:http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++编程-HOWTO-7.html
如果您对代码示例有疑问,请留下评论,我会解释。
仅仅因为它没有实现称为迭代器的typedef或重载<<运算符,并不意味着它是错误的代码。我经常使用C函数。例如,printf和scanf都比std::cin和std::cout快(很明显),fopen语法对二进制类型更友好,它们也倾向于生成更小的EXE。
不要被这种“优雅胜过性能”的交易所吸引。
使用vector作为基类的快速版本,可完全访问其所有运算符:
// Split string into parts.
class Split : public std::vector<std::string>
{
public:
Split(const std::string& str, char* delimList)
{
size_t lastPos = 0;
size_t pos = str.find_first_of(delimList);
while (pos != std::string::npos)
{
if (pos != lastPos)
push_back(str.substr(lastPos, pos-lastPos));
lastPos = pos + 1;
pos = str.find_first_of(delimList, lastPos);
}
if (lastPos < str.length())
push_back(str.substr(lastPos, pos-lastPos));
}
};
用于填充STL集的示例:
std::set<std::string> words;
Split split("Hello,World", ",");
words.insert(split.begin(), split.end());
我的代码是:
#include <list>
#include <string>
template<class StringType = std::string, class ContainerType = std::list<StringType> >
class DSplitString:public ContainerType
{
public:
explicit DSplitString(const StringType& strString, char cChar, bool bSkipEmptyParts = true)
{
size_t iPos = 0;
size_t iPos_char = 0;
while(StringType::npos != (iPos_char = strString.find(cChar, iPos)))
{
StringType strTemp = strString.substr(iPos, iPos_char - iPos);
if((bSkipEmptyParts && !strTemp.empty()) || (!bSkipEmptyParts))
push_back(strTemp);
iPos = iPos_char + 1;
}
}
explicit DSplitString(const StringType& strString, const StringType& strSub, bool bSkipEmptyParts = true)
{
size_t iPos = 0;
size_t iPos_char = 0;
while(StringType::npos != (iPos_char = strString.find(strSub, iPos)))
{
StringType strTemp = strString.substr(iPos, iPos_char - iPos);
if((bSkipEmptyParts && !strTemp.empty()) || (!bSkipEmptyParts))
push_back(strTemp);
iPos = iPos_char + strSub.length();
}
}
};
例子:
#include <iostream>
#include <string>
int _tmain(int argc, _TCHAR* argv[])
{
DSplitString<> aa("doicanhden1;doicanhden2;doicanhden3;", ';');
for each (std::string var in aa)
{
std::cout << var << std::endl;
}
std::cin.get();
return 0;
}
值得一提的是,这里有另一种从输入字符串中提取令牌的方法,仅依赖于标准库设施。这是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"));
}
可以使用相同的通用复制算法将提取的令牌插入到容器中,而不是将其复制到输出流中。
vector<string> tokens;
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter(tokens));
…或直接创建矢量:
vector<string> tokens{istream_iterator<string>{iss},
istream_iterator<string>{}};