Skip to content
C++ Better Explained
Go back
How to Trim Whitespace from a String in C++

How to Trim Whitespace from a String in C++

Short answer: C++ has no built-in trim(). Use find_first_not_of and find_last_not_of to locate the first and last non-whitespace characters, then take the substring between them. Copy-paste function below.


The Copy-Paste Trim Function

#include <iostream>
#include <string>

const std::string WHITESPACE = " \t\n\r\f\v";

std::string ltrim(const std::string& s) {
    size_t start = s.find_first_not_of(WHITESPACE);
    return (start == std::string::npos) ? "" : s.substr(start);
}

std::string rtrim(const std::string& s) {
    size_t end = s.find_last_not_of(WHITESPACE);
    return (end == std::string::npos) ? "" : s.substr(0, end + 1);
}

std::string trim(const std::string& s) {
    return rtrim(ltrim(s));
}

int main() {
    std::string messy = "   hello world   ";
    std::cout << "[" << trim(messy) << "]\n";   // [hello world]
    std::cout << "[" << ltrim(messy) << "]\n";  // [hello world   ]
    std::cout << "[" << rtrim(messy) << "]\n";  // [   hello world]
}

That is the whole job. The rest of this article explains why it works and the traps around it.

Why There Is No std::string::trim

std::string is a container of bytes, not a text type. It does not assume your data is human-readable text, so it does not assume you want whitespace removed. Trimming also needs a decision — is a non-breaking space whitespace? what about a null byte? — and the standard library avoids making that choice for you.

The practical consequence: every C++ codebase ends up with its own small trim helper. Put the one above in a utility header and stop rewriting it.

Learning C++ properly? The C++ Better Explained Ebook covers strings, vectors and the STL in plain English — 87 pages, just $19.

How find_first_not_of Actually Works

find_first_not_of scans from the left and returns the index of the first character that is not in the set you pass:

std::string s = "   abc";
size_t i = s.find_first_not_of(" ");  // 3 — index of 'a'

find_last_not_of does the same from the right:

std::string s = "abc   ";
size_t i = s.find_last_not_of(" ");   // 2 — index of 'c'

So substr(start, end - start + 1) gives you everything between the first and last real characters.

The All-Whitespace Trap

If the string contains nothing but whitespace, find_first_not_of returns std::string::npos — a huge unsigned value. Passing that to substr throws std::out_of_range, or silently produces garbage if you do arithmetic on it first:

std::string blank = "     ";
size_t start = blank.find_first_not_of(WHITESPACE);  // npos
// blank.substr(start);  // throws std::out_of_range

That is exactly why both functions above check for npos and return an empty string. Skipping that check is the single most common bug in hand-written trim code.

Trimming in Place

If you would rather modify the string instead of returning a copy, erase from both ends:

void trimInPlace(std::string& s) {
    s.erase(0, s.find_first_not_of(WHITESPACE));
    size_t end = s.find_last_not_of(WHITESPACE);
    if (end != std::string::npos) s.erase(end + 1);
    else s.clear();
}

erase(0, n) removes the first n characters, and erase(pos) removes everything from pos onward.

Trimming Other Characters

Nothing here is whitespace-specific. Pass whatever set you want to strip:

std::string quoted = "\"hello\"";
std::string bare = trimChars(quoted, "\"");   // hello

std::string padded = "000042000";
std::string digits = trimChars(padded, "0");  // 42

with:

std::string trimChars(const std::string& s, const std::string& chars) {
    size_t start = s.find_first_not_of(chars);
    if (start == std::string::npos) return "";
    size_t end = s.find_last_not_of(chars);
    return s.substr(start, end - start + 1);
}

Useful for stripping quotes off CSV fields or leading zeros off IDs.

Trimming Input from cin

The most common reason people need trim is user input. Note that std::getline already strips the newline, but it keeps any spaces the user typed:

std::string name;
std::getline(std::cin, name);
name = trim(name);   // "  Sahil  " becomes "Sahil"

If you are mixing cin >> and getline and getting skipped input, that is a different problem — see clearing the input buffer with cin.ignore.

Removing All Spaces Instead

Trim only touches the ends. To delete every space in the string, use the erase-remove idiom:

#include <algorithm>

std::string s = "a b c d";
s.erase(std::remove(s.begin(), s.end(), ' '), s.end());
std::cout << s;   // abcd

std::remove shuffles the unwanted characters to the back and returns an iterator to the new logical end; erase then actually shortens the string. It does not remove anything on its own — forgetting the erase half is a classic mistake.

Quick Reference

GoalCode
Trim both endstrim(s) from above
Trim left onlys.erase(0, s.find_first_not_of(WS))
Trim right onlys.erase(s.find_last_not_of(WS) + 1)
Strip specific charstrimChars(s, "\"")
Remove all spacess.erase(std::remove(s.begin(), s.end(), ' '), s.end())

Take Your C++ Further

If you want strings, vectors and the STL explained properly rather than looked up one function at a time, the C++ Better Explained Ebook covers the fundamentals in plain English with diagrams and runnable examples. Just $19.

👉 Get the C++ Better Explained Ebook — $19


📋

Free Download: The 10 Mistakes Every C++ Beginner Makes

A free 1-page checklist that shows the exact traps that slow down every C++ beginner — so you can avoid them from day one.

🔒 No spam. Unsubscribe anytime.


Share this post on:

Written by

Sahil Bora

Software Engineer. Author and creator of C++ Better Explained.


Previous Post
How to Reverse a Vector in C++ (std::reverse and More)
Next Post
How to Clear the Console Screen in C++ (Every Method Explained)

Keep Learning