Standard Library[lib]

C++ split string: 3 ways with code (getline, find, views)

Section
Standard Library [lib]
Standard
C++17
Compilers
MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2, Clang 23.1 (libc++)
Published
Length
7 min read
In this answer8 clauses
  1. 1Does C++ have a split function?
  2. 2How do you split a string on a character with getline?
  3. 3How do you split on a string delimiter with find and substr?
  4. 4How do you split a string on whitespace?
  5. 5How do you split a string with std::views::split (C++20)?
  6. 6What happens with empty fields and a trailing delimiter?
  7. 7What about strtok and boost::split?
  8. 8Which way should you use?

Abstract

std::string has no split member, so to split a string in C++ you write a short loop. For a one-character delimiter, put the text in a std::istringstream and call std::getline with that character as its third argument until the text runs out; for a longer delimiter, loop with find and substr. Since C++20, std::views::split yields the pieces, and since C++23 std::ranges::to collects them into a vector. After a trailing delimiter the getline loop gives no empty last piece; the other two do.

A long bar of hatched character cells cut into three pieces of three, five and four cells, set slightly apart; a blue vertical cut line runs through each of the two gaps where the delimiters were.
Figure 1 — One string, cut where the delimiter was.

To split a string in C++, write a short loop: std::string has no split member. The shortest puts the text in a std::istringstream and calls std::getline(in, piece, ',') until the text runs out, adding each piece to a vector. For a delimiter of several characters, loop with find and substr; since C++20, std::views::split cuts the pieces for you.

[Example 1:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

int main() {
    std::istringstream in("red,green,blue");
    std::vector<std::string> pieces;
    std::string piece;
    while (std::getline(in, piece, ',')) {
        pieces.push_back(piece);
    }

    std::cout << pieces.size() << " pieces\n";
    for (const std::string& p : pieces) {
        std::cout << p << '\n';
    }
}

— end example]

It printed:

[Example 2:
3 pieces
red
green
blue

— end example]

The samples are C++17, except the std::views::split ones (C++20, and C++23 for std::ranges::to), built with MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2 and Clang 23.1 (libc++); all four printed the same for every sample. Since When lists compiler support for each standard’s features.

Does C++ have a split function?

Not as a member of std::string, in any standard up to C++26. You build the split from library pieces, and the delimiter decides which:

Your delimiter Use
One character, such as ',' std::getline on a std::istringstream
Several characters, such as ", " a loop of find and substr
Either, in C++20 or later std::views::split

How do you split a string on a character with getline?

std::getline(in, piece, ',') reads characters up to the next comma, stores them in piece and throws the comma away; the loop ends when nothing is left to read. In the program above, std::istringstream, from <sstream>, is a stream that reads from a string in memory. std::getline is the same function that reads a whole line from std::cin; here it reads from the text, and its third argument is the delimiter, one char.

The last piece, blue, has no comma after it: getline reads it up to the end of the text and still returns it. The next call reads nothing at all, so it fails, and the loop stops.

The text red,green,blue as fourteen character cells, its two commas shaded and labelled delimiter. Arrows lead from the runs red, green and blue down into slots 0, 1 and 2 of a vector named pieces; each comma is marked dropped.
Figure 2 — Splitting cuts the text at every delimiter, keeps the pieces in order and drops the delimiters.

How do you split on a string delimiter with find and substr?

Write a split() function: find the delimiter from the current position, cut the piece before it, jump past it and repeat; what is left after the last delimiter is the last piece. It works for ", ", "::" or any other delimiter:

[Example 3:
std::vector<std::string> split(const std::string& text,
                               const std::string& delimiter) {
    if (delimiter.empty()) {
        return {text};  // nothing to cut on: the whole text
    }
    std::vector<std::string> pieces;
    std::string::size_type start = 0;
    std::string::size_type end = text.find(delimiter);
    while (end != std::string::npos) {
        pieces.push_back(text.substr(start, end - start));
        start = end + delimiter.size();  // jump past the delimiter
        end = text.find(delimiter, start);
    }
    pieces.push_back(text.substr(start));  // the rest is the last piece
    return pieces;
}
// ...
print(split("red, green, blue", ", "));
print(split("a::b::c", "::"));
print(split("red, green, blue", ""));

— end example]

print writes the count and each piece in brackets. It printed:

[Example 4:
3: [red][green][blue]
3: [a][b][c]
1: [red, green, blue]

— end example]

find returns the index where the next delimiter starts, or std::string::npos when none is left, which ends the loop. substr(start, end - start) copies the piece before it: its second argument is a length, not an end index. The early return gives an empty delimiter the whole text as one piece, the third line.

How do you split a string on whitespace?

Read with >> instead of getline: in >> word skips any run of spaces, tabs and newlines, then reads up to the next one, so while (in >> word) gives no empty pieces.

[Example 5:
std::istringstream in("  the quick   brown fox ");
std::vector<std::string> words;
std::string word;
while (in >> word) {  // skips every run of whitespace first
    words.push_back(word);
}

— end example]

All four found the four words, [the][quick][brown][fox], and a text mixing tabs and newlines split into its words the same way. std::getline(in, piece, ' ') is the wrong tool here: on the same text it gave 8 pieces, four of them empty.

How do you split a string with std::views::split (C++20)?

Since C++20, text | std::views::split(',') hands you the pieces one at a time. Each piece is a view of the characters inside the original text, a subrange ([range.split]), not a new string, so you make a string only when you need one:

[Example 6:
std::string text = "red,green,blue";
for (auto piece : text | std::views::split(',')) {  // C++20
    std::string s(piece.begin(), piece.end());  // piece -> string
    std::cout << '[' << s << ']';
}

— end example]

It printed [red][green][blue], and std::views::split(", "sv) cut "red, green, blue" the same way, because std::views::split takes one character or a run of them as its delimiter. It needs <ranges>, C++20 (-std=c++20, /std:c++20) and GCC 12, or Clang 16 with libc++, or later: GCC 10 and 11 ship an earlier split_view whose pieces std::string(piece.begin(), piece.end()) cannot take. Built as C++17, all four rejected it.

Since C++23, std::ranges::to collects the pieces into a vector in one statement:

[Example 7:
auto pieces = text | std::views::split(',')
            | std::ranges::to<std::vector<std::string>>();  // C++23

— end example]

All four built it as C++23, printed the three pieces and rejected it as C++20. Name the whole element type: std::ranges::to<std::vector>() would deduce a vector of subranges, not of strings.

What happens with empty fields and a trailing delimiter?

The ways disagree at the end of the text. All three keep the empty field between two commas, but after a trailing comma the getline loop stops, while split() and views::split add one more, empty piece. For "a,,b," all four printed:

Way Pieces What it gave
getline loop 3 [a][][b]
find and substr, the split() above 4 [a][][b][]
std::views::split 4 [a][][b][]

getline drops that last piece because the call after the trailing comma reads nothing and fails. An empty text differs too: the getline loop and views::split gave no pieces, but split() returned one empty piece, so check for it if an empty input should mean an empty list.

What about strtok and boost::split?

Avoid std::strtok: it changes the text it splits and skips empty fields.

[Example 8:
char buffer[] = "a,,b,";
for (char* token = std::strtok(buffer, ","); token != nullptr;
     token = std::strtok(nullptr, ",")) {
    std::cout << '[' << token << "]\n";
}
std::cout << "buffer now reads: " << buffer << '\n';

— end example]

It printed:

[Example 9:
[a]
[b]
buffer now reads: a

— end example]

It wrote a zero byte over each comma it cut at, which is why the array now reads just a. It also remembers its place between calls, so two splits cannot interleave, and the standard does not require it to be safe to call from two threads at once; on Windows, MSVC (C4996) and Clang warn that it may be unsafe.

In a project that already uses Boost, boost::split(result, input, is_any_of(","), token_compress_on) (declared as boost::algorithm::split, from <boost/algorithm/string.hpp>) fills a container in one call; token_compress_on merges adjacent separators (Boost’s usage notes).

Which way should you use?

You have Use
A one-character delimiter the getline loop
A longer delimiter, in C++17 split() with find and substr
A trailing empty field that must count split() or std::views::split, not getline
Words separated by spaces, tabs or newlines while (in >> word)
C++20, and you only read the pieces std::views::split
C++23, and you want a vector std::ranges::to after views::split
Numbers, such as "10,20,30" the getline loop, then std::stoi on each piece

More answers on strings and the rest of the library are in the Standard library section.

Questions

How do you split a string by a comma in C++?

Put the string in a std::istringstream and call std::getline(in, piece, ‘,’) in a loop, pushing each piece into a std::vector of std::string. Each call reads up to the next comma, stores what it read and throws the comma away. On “red,green,blue” it gave red, green and blue; a comma at the very end adds no empty piece.

How do you split a string by a space in C++?

Read it word by word with >>: while (in >> word) on a std::istringstream skips every run of spaces, tabs and newlines, so “ the quick brown fox “ gave four words and no empty ones. std::getline with ‘ ‘ as the delimiter cuts at every single space instead: on the same text it gave 8 pieces, four of them empty.

How do you split a string into a vector in C++?

Loop and push_back each piece: the getline loop and the find and substr loop both fill a std::vector of std::string. Since C++23, text | std::views::split(',') | std::ranges::to<std::vector<std::string>>() builds the vector in one statement. Name the element type, or the vector holds subranges instead of strings.

Is there a std::string split function?

No. std::string has no split member in any standard up to C++26, so you write the loop with std::getline or with find and substr. Since C++20, std::views::split from <ranges> is the closest the standard library comes: it yields each piece as a view of the original characters, which std::string(piece.begin(), piece.end()) turns into a string.

How do you split a string by multiple delimiters in C++?

Search with find_first_of instead of find: it stops at the first character that is any of a set, so a loop calling find_first_of(“,;”) and stepping one character past each match cut “red,green;blue” into red, green and blue. Each character of the set is a delimiter of its own, so the set “, “ cuts “red, green” at the comma and again at the space, giving red, an empty piece and green.

Sources

  1. std::getlinecppreference.com
  2. std::basic_string::findcppreference.com
  3. std::ranges::split_view, std::views::splitcppreference.com
  4. std::ranges::tocppreference.com
  5. std::strtokcppreference.com
  6. [range.split] Split viewC++ standard working draft
  7. Boost String Algorithms Library: UsageBoost

Read next

  1. C++ std::find: search a vector, array or stringStandard Library · Miriam Castellanos · written for C++17
  2. C++ string find: how to find a substring and check nposStandard Library · Miriam Castellanos · written for C++17
  3. C++ random number: how to generate one in a rangeStandard Library · Miriam Castellanos · written for C++11