I use the following code:
namespace Core
{
typedef std::wstring String;
void SplitString(const Core::String& input, const Core::String& splitter, std::list<Core::String>& output)
{
if (splitter.empty())
{
throw std::invalid_argument(); // for example
}
std::list<Core::String> lines;
Core::String::size_type offset = 0;
for (;;)
{
Core::String::size_type splitterPos = input.find(splitter, offset);
if (splitterPos != Core::String::npos)
{
lines.push_back(input.substr(offset, splitterPos - offset));
offset = splitterPos + splitter.size();
}
else
{
lines.push_back(input.substr(offset));
break;
}
}
lines.swap(output);
}
}
// gtest:
class SplitStringTest: public testing::Test
{
};
TEST_F(SplitStringTest, EmptyStringAndSplitter)
{
std::list<Core::String> result;
ASSERT_ANY_THROW(Core::SplitString(Core::String(), Core::String(), result));
}
TEST_F(SplitStringTest, NonEmptyStringAndEmptySplitter)
{
std::list<Core::String> result;
ASSERT_ANY_THROW(Core::SplitString(L"xy", Core::String(), result));
}
TEST_F(SplitStringTest, EmptyStringAndNonEmptySplitter)
{
std::list<Core::String> result;
Core::SplitString(Core::String(), Core::String(L","), result);
ASSERT_EQ(1, result.size());
ASSERT_EQ(Core::String(), *result.begin());
}
TEST_F(SplitStringTest, OneCharSplitter)
{
std::list<Core::String> result;
Core::SplitString(L"x,y", L",", result);
ASSERT_EQ(2, result.size());
ASSERT_EQ(L"x", *result.begin());
ASSERT_EQ(L"y", *result.rbegin());
Core::SplitString(L",xy", L",", result);
ASSERT_EQ(2, result.size());
ASSERT_EQ(Core::String(), *result.begin());
ASSERT_EQ(L"xy", *result.rbegin());
Core::SplitString(L"xy,", L",", result);
ASSERT_EQ(2, result.size());
ASSERT_EQ(L"xy", *result.begin());
ASSERT_EQ(Core::String(), *result.rbegin());
}
TEST_F(SplitStringTest, TwoCharsSplitter)
{
std::list<Core::String> result;
Core::SplitString(L"x,.y,z", L",.", result);
ASSERT_EQ(2, result.size());
ASSERT_EQ(L"x", *result.begin());
ASSERT_EQ(L"y,z", *result.rbegin());
Core::SplitString(L"x,,y,z", L",,", result);
ASSERT_EQ(2, result.size());
ASSERT_EQ(L"x", *result.begin());
ASSERT_EQ(L"y,z", *result.rbegin());
}
TEST_F(SplitStringTest, RecursiveSplitter)
{
std::list<Core::String> result;
Core::SplitString(L",,,", L",,", result);
ASSERT_EQ(2, result.size());
ASSERT_EQ(Core::String(), *result.begin());
ASSERT_EQ(L",", *result.rbegin());
Core::SplitString(L",.,.,", L",.,", result);
ASSERT_EQ(2, result.size());
ASSERT_EQ(Core::String(), *result.begin());
ASSERT_EQ(L".,", *result.rbegin());
Core::SplitString(L"x,.,.,y", L",.,", result);
ASSERT_EQ(2, result.size());
ASSERT_EQ(L"x", *result.begin());
ASSERT_EQ(L".,y", *result.rbegin());
Core::SplitString(L",.,,.,", L",.,", result);
ASSERT_EQ(3, result.size());
ASSERT_EQ(Core::String(), *result.begin());
ASSERT_EQ(Core::String(), *(++result.begin()));
ASSERT_EQ(Core::String(), *result.rbegin());
}
TEST_F(SplitStringTest, NullTerminators)
{
std::list<Core::String> result;
Core::SplitString(L"xy", Core::String(L"\0", 1), result);
ASSERT_EQ(1, result.size());
ASSERT_EQ(L"xy", *result.begin());
Core::SplitString(Core::String(L"x\0y", 3), Core::String(L"\0", 1), result);
ASSERT_EQ(2, result.size());
ASSERT_EQ(L"x", *result.begin());
ASSERT_EQ(L"y", *result.rbegin());
}
while (iss) { string subs; iss >> subs; cout << "Substring: " << sub << endl; }
– Eddistring sub; while (iss >> sub) cout << "Substring: " << sub << '\n';
– Stockwell