/commands/cpp/split-string-by-delimiter
c++ split a string by delimiter (getline, find, std::views::split)
- tool
- C++
- versions
- C++98+ (getline), C++20 (views::split), C++23 (ranges::to)
- os
- any
The portable way to split a string by a single-character delimiter in C++ is a std::getline loop over an std::istringstream: while (std::getline(iss, token, ',')) parts.push_back(token);. For a delimiter of several characters, loop with find and substr. C++20 adds std::views::split, which splits lazily without copying.
Three ways
The example uses Clang 20 from the ziglang package on PyPI (with libc++), run through uv; cxx stands for it. On your machine, write g++ or clang++:
cxx() { uv run -q --no-project --python 3.13 --with ziglang==0.15.1 python -m ziglang c++ -fno-color-diagnostics "$@"; }
cat > split.cpp <<'EOF'
#include <iostream>
#include <ranges>
#include <sstream>
#include <string>
#include <string_view>
#include <vector>
std::vector<std::string> split_getline(const std::string& s, char delim) {
std::vector<std::string> out;
std::istringstream iss(s);
for (std::string token; std::getline(iss, token, delim);) out.push_back(token);
return out;
}
std::vector<std::string> split_find(const std::string& s, const std::string& delim) {
std::vector<std::string> out;
std::size_t start = 0, pos;
while ((pos = s.find(delim, start)) != std::string::npos) {
out.push_back(s.substr(start, pos - start));
start = pos + delim.size();
}
out.push_back(s.substr(start));
return out;
}
void print(const char* label, const std::vector<std::string>& v) {
std::cout << label << " (" << v.size() << "):";
for (const auto& t : v) std::cout << " [" << t << "]";
std::cout << '\n';
}
int main() {
print("getline ','", split_getline("a,b,,c,", ','));
print("find \", \"", split_find("red, green, blue", ", "));
print("find ',' ", split_find("a,b,,c,", ","));
std::cout << "views::split:";
for (auto part : std::string_view("x-y-z") | std::views::split('-'))
std::cout << " [" << std::string_view(part.begin(), part.end()) << "]";
std::cout << '\n';
std::istringstream words(" split on\twhitespace ");
std::cout << "operator>>:";
for (std::string w; words >> w;) std::cout << " [" << w << "]";
std::cout << '\n';
}
EOF
cxx -std=c++20 -Wall -Wextra split.cpp -o split && ./splitOutput
getline ',' (4): [a] [b] [] [c] find ", " (3): [red] [green] [blue] find ',' (5): [a] [b] [] [c] [] views::split: [x] [y] [z] operator>>: [split] [on] [whitespace]
Note the different handling of empty fields: the getline loop keeps the empty field between two commas but drops the empty one after a trailing comma, while the find loop keeps both. Pick the version that matches your format (CSV-like data usually needs the find behaviour).
Methods compared
| Method | Standard | Notes |
|---|---|---|
| getline(iss, token, delim) loop | C++98 | Single-character delimiter; no token after a trailing delimiter |
| find + substr loop | C++98 | Any delimiter string; keeps every empty field |
| std::views::split(delim) | C++20 | Lazy view, no copies; convert each part to string_view or string |
| views::split | ranges::to<std::vector<std::string>>() | C++23 | Collect the pieces in one expression |
| iss >> word loop | C++98 | Splits on any whitespace, never yields empty tokens |
| std::regex / sregex_token_iterator | C++11 | Regular-expression delimiters; much slower |
Pitfalls
- Missing headers.
std::istringstreamneeds<sstream>andstd::viewsneeds<ranges>; without them the compiler reports no member named ... in namespace std. - Standard too old.
std::views::splitrequires-std=c++20and a recent standard library (GCC 12+, Clang 16+ with libc++ for the fixed C++20 semantics). - Dangling string_view. Views returned from
views::splitpoint into the original string; keep it alive while you use them. - Windows line endings. Splitting lines read from a CRLF file leaves a
\rat the end of the last field; strip it.
Confirm it worked
Print each token between brackets, as in the example, so empty tokens and stray spaces are visible, and test a string with a leading, a doubled and a trailing delimiter.
FAQ
Does C++ have a built-in split function?
Not one that returns a vector of strings. C++20 adds std::views::split, a lazy view over the pieces; together with C++23 std::ranges::to you can collect them into a container. Before that, a getline loop or find/substr is the usual way.
How do I split on any whitespace?
Read words with operator>> from an std::istringstream: while (iss >> word). It skips spaces, tabs and newlines and never produces empty tokens.
How do I split by a multi-character delimiter such as ", "?
getline only takes a single character. Use the find/substr loop with the delimiter string and advance by its length, or std::views::split with a string_view delimiter (C++20).