如何迭代由空格分隔的单词组成的字符串中的单词?
注意,我对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);
}
是的,我看了所有30个例子。
我找不到一个适用于多字符分隔符的split版本,所以这里是我的:
#include <string>
#include <vector>
using namespace std;
vector<string> split(const string &str, const string &delim)
{
const auto delim_pos = str.find(delim);
if (delim_pos == string::npos)
return {str};
vector<string> ret{str.substr(0, delim_pos)};
auto tail = split(str.substr(delim_pos + delim.size(), string::npos), delim);
ret.insert(ret.end(), tail.begin(), tail.end());
return ret;
}
可能不是最有效的实现,但它是一个非常简单的递归解决方案,只使用<string>和<vector>。
啊,它是用C++11编写的,但这段代码没有什么特别之处,因此您可以很容易地将其改编为C++98。
如果您需要通过非空格符号解析字符串,则字符串流可能很方便:
string s = "Name:JAck; Spouse:Susan; ...";
string dummy, name, spouse;
istringstream iss(s);
getline(iss, dummy, ':');
getline(iss, name, ';');
getline(iss, dummy, ':');
getline(iss, spouse, ';')
#include <iostream>
#include <string>
#include <deque>
std::deque<std::string> split(
const std::string& line,
std::string::value_type delimiter,
bool skipEmpty = false
) {
std::deque<std::string> parts{};
if (!skipEmpty && !line.empty() && delimiter == line.at(0)) {
parts.push_back({});
}
for (const std::string::value_type& c : line) {
if (
(
c == delimiter
&&
(skipEmpty ? (!parts.empty() && !parts.back().empty()) : true)
)
||
(c != delimiter && parts.empty())
) {
parts.push_back({});
}
if (c != delimiter) {
parts.back().push_back(c);
}
}
if (skipEmpty && !parts.empty() && parts.back().empty()) {
parts.pop_back();
}
return parts;
}
void test(const std::string& line) {
std::cout << line << std::endl;
std::cout << "skipEmpty=0 |";
for (const std::string& part : split(line, ':')) {
std::cout << part << '|';
}
std::cout << std::endl;
std::cout << "skipEmpty=1 |";
for (const std::string& part : split(line, ':', true)) {
std::cout << part << '|';
}
std::cout << std::endl;
std::cout << std::endl;
}
int main() {
test("foo:bar:::baz");
test("");
test("foo");
test(":");
test("::");
test(":foo");
test("::foo");
test(":foo:");
test(":foo::");
return 0;
}
输出:
foo:bar:::baz
skipEmpty=0 |foo|bar|||baz|
skipEmpty=1 |foo|bar|baz|
skipEmpty=0 |
skipEmpty=1 |
foo
skipEmpty=0 |foo|
skipEmpty=1 |foo|
:
skipEmpty=0 |||
skipEmpty=1 |
::
skipEmpty=0 ||||
skipEmpty=1 |
:foo
skipEmpty=0 ||foo|
skipEmpty=1 |foo|
::foo
skipEmpty=0 |||foo|
skipEmpty=1 |foo|
:foo:
skipEmpty=0 ||foo||
skipEmpty=1 |foo|
:foo::
skipEmpty=0 ||foo|||
skipEmpty=1 |foo|
我的实施可以是另一种解决方案:
std::vector<std::wstring> SplitString(const std::wstring & String, const std::wstring & Seperator)
{
std::vector<std::wstring> Lines;
size_t stSearchPos = 0;
size_t stFoundPos;
while (stSearchPos < String.size() - 1)
{
stFoundPos = String.find(Seperator, stSearchPos);
stFoundPos = (stFoundPos == std::string::npos) ? String.size() : stFoundPos;
Lines.push_back(String.substr(stSearchPos, stFoundPos - stSearchPos));
stSearchPos = stFoundPos + Seperator.size();
}
return Lines;
}
测试代码:
std::wstring MyString(L"Part 1SEPsecond partSEPlast partSEPend");
std::vector<std::wstring> Parts = IniFile::SplitString(MyString, L"SEP");
std::wcout << L"The string: " << MyString << std::endl;
for (std::vector<std::wstring>::const_iterator it=Parts.begin(); it<Parts.end(); ++it)
{
std::wcout << *it << L"<---" << std::endl;
}
std::wcout << std::endl;
MyString = L"this,time,a,comma separated,string";
std::wcout << L"The string: " << MyString << std::endl;
Parts = IniFile::SplitString(MyString, L",");
for (std::vector<std::wstring>::const_iterator it=Parts.begin(); it<Parts.end(); ++it)
{
std::wcout << *it << L"<---" << std::endl;
}
测试代码的输出:
The string: Part 1SEPsecond partSEPlast partSEPend
Part 1<---
second part<---
last part<---
end<---
The string: this,time,a,comma separated,string
this<---
time<---
a<---
comma separated<---
string<---