How to trim a std::string?

C++TrimStdstring

C++ Problem Overview


I'm currently using the following code to right-trim all the std::strings in my programs:

std::string s;
s.erase(s.find_last_not_of(" \n\r\t")+1);

It works fine, but I wonder if there are some end-cases where it might fail?

Of course, answers with elegant alternatives and also left-trim solution are welcome.

C++ Solutions


Solution 1 - C++

EDIT Since c++17, some parts of the standard library were removed. Fortunately, starting with c++11, we have lambdas which are a superior solution.

#include <algorithm> 
#include <cctype>
#include <locale>

// trim from start (in place)
static inline void ltrim(std::string &s) {
	s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
		return !std::isspace(ch);
	}));
}

// trim from end (in place)
static inline void rtrim(std::string &s) {
	s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
		return !std::isspace(ch);
	}).base(), s.end());
}

// trim from both ends (in place)
static inline void trim(std::string &s) {
	ltrim(s);
	rtrim(s);
}

// trim from start (copying)
static inline std::string ltrim_copy(std::string s) {
	ltrim(s);
	return s;
}

// trim from end (copying)
static inline std::string rtrim_copy(std::string s) {
	rtrim(s);
	return s;
}

// trim from both ends (copying)
static inline std::string trim_copy(std::string s) {
	trim(s);
	return s;
}

Thanks to https://stackoverflow.com/a/44973498/524503 for bringing up the modern solution.

Original answer:

I tend to use one of these 3 for my trimming needs:

#include <algorithm> 
#include <functional> 
#include <cctype>
#include <locale>

// trim from start
static inline std::string &ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(),
            std::not1(std::ptr_fun<int, int>(std::isspace))));
    return s;
}

// trim from end
static inline std::string &rtrim(std::string &s) {
    s.erase(std::find_if(s.rbegin(), s.rend(),
            std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
    return s;
}

// trim from both ends
static inline std::string &trim(std::string &s) {
    return ltrim(rtrim(s));
}

They are fairly self-explanatory and work very well.

EDIT: BTW, I have std::ptr_fun in there to help disambiguate std::isspace because there is actually a second definition which supports locales. This could have been a cast just the same, but I tend to like this better.

EDIT: To address some comments about accepting a parameter by reference, modifying and returning it. I Agree. An implementation that I would likely prefer would be two sets of functions, one for in place and one which makes a copy. A better set of examples would be:

#include <algorithm> 
#include <functional> 
#include <cctype>
#include <locale>

// trim from start (in place)
static inline void ltrim(std::string &s) {
	s.erase(s.begin(), std::find_if(s.begin(), s.end(),
            std::not1(std::ptr_fun<int, int>(std::isspace))));
}

// trim from end (in place)
static inline void rtrim(std::string &s) {
	s.erase(std::find_if(s.rbegin(), s.rend(),
            std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
}

// trim from both ends (in place)
static inline void trim(std::string &s) {
	ltrim(s);
	rtrim(s);
}

// trim from start (copying)
static inline std::string ltrim_copy(std::string s) {
	ltrim(s);
	return s;
}

// trim from end (copying)
static inline std::string rtrim_copy(std::string s) {
	rtrim(s);
	return s;
}

// trim from both ends (copying)
static inline std::string trim_copy(std::string s) {
	trim(s);
	return s;
}

I am keeping the original answer above though for context and in the interest of keeping the high voted answer still available.

Solution 2 - C++

Using Boost's string algorithms would be easiest:

#include <boost/algorithm/string.hpp>

std::string str("hello world! ");
boost::trim_right(str);

str is now "hello world!". There's also trim_left and trim, which trims both sides.


If you add _copy suffix to any of above function names e.g. trim_copy, the function will return a trimmed copy of the string instead of modifying it through a reference.

If you add _if suffix to any of above function names e.g. trim_copy_if, you can trim all characters satisfying your custom predicate, as opposed to just whitespaces.

Solution 3 - C++

What you are doing is fine and robust. I have used the same method for a long time and I have yet to find a faster method:

const char* ws = " \t\n\r\f\v";

// trim from end of string (right)
inline std::string& rtrim(std::string& s, const char* t = ws)
{
	s.erase(s.find_last_not_of(t) + 1);
	return s;
}

// trim from beginning of string (left)
inline std::string& ltrim(std::string& s, const char* t = ws)
{
	s.erase(0, s.find_first_not_of(t));
	return s;
}

// trim from both ends of string (right then left)
inline std::string& trim(std::string& s, const char* t = ws)
{
	return ltrim(rtrim(s, t), t);
}

By supplying the characters to be trimmed you have the flexibility to trim non-whitespace characters and the efficiency to trim only the characters you want trimmed.

Solution 4 - C++

Use the following code to right trim (trailing) spaces and tab characters from std::strings (ideone):

// trim trailing spaces
size_t endpos = str.find_last_not_of(" \t");
size_t startpos = str.find_first_not_of(" \t");
if( std::string::npos != endpos )
{
	str = str.substr( 0, endpos+1 );
	str = str.substr( startpos );
}
else {
	str.erase(std::remove(std::begin(str), std::end(str), ' '), std::end(str));
}

And just to balance things out, I'll include the left trim code too (ideone):

// trim leading spaces
size_t startpos = str.find_first_not_of(" \t");
if( string::npos != startpos )
{
    str = str.substr( startpos );
}

Solution 5 - C++

Bit late to the party, but never mind. Now C++11 is here, we have lambdas and auto variables. So my version, which also handles all-whitespace and empty strings, is:

#include <cctype>
#include <string>
#include <algorithm>

inline std::string trim(const std::string &s)
{
   auto wsfront=std::find_if_not(s.begin(),s.end(),[](int c){return std::isspace(c);});
   auto wsback=std::find_if_not(s.rbegin(),s.rend(),[](int c){return std::isspace(c);}).base();
   return (wsback<=wsfront ? std::string() : std::string(wsfront,wsback));
}

We could make a reverse iterator from wsfront and use that as the termination condition in the second find_if_not but that's only useful in the case of an all-whitespace string, and gcc 4.8 at least isn't smart enough to infer the type of the reverse iterator (std::string::const_reverse_iterator) with auto. I don't know how expensive constructing a reverse iterator is, so YMMV here. With this alteration, the code looks like this:

inline std::string trim(const std::string &s)
{
   auto  wsfront=std::find_if_not(s.begin(),s.end(),[](int c){return std::isspace(c);});
   return std::string(wsfront,std::find_if_not(s.rbegin(),std::string::const_reverse_iterator(wsfront),[](int c){return std::isspace(c);}).base());
}

Solution 6 - C++

Try this, it works for me.

inline std::string trim(std::string& str)
{
    str.erase(str.find_last_not_of(' ')+1);			//suffixing spaces
    str.erase(0, str.find_first_not_of(' '));		//prefixing spaces
    return str;
}

Solution 7 - C++

http://ideone.com/nFVtEo

std::string trim(const std::string &s)
{
	std::string::const_iterator it = s.begin();
	while (it != s.end() && isspace(*it))
		it++;

	std::string::const_reverse_iterator rit = s.rbegin();
	while (rit.base() != it && isspace(*rit))
		rit++;

	return std::string(it, rit.base());
}

Solution 8 - C++

I like tzaman's solution, the only problem with it is that it doesn't trim a string containing only spaces.

To correct that 1 flaw, add a str.clear() in between the 2 trimmer lines

std::stringstream trimmer;
trimmer << str;
str.clear();
trimmer >> str;

Solution 9 - C++

With C++17 you can use basic_string_view::remove_prefix and basic_string_view::remove_suffix:

std::string_view trim(std::string_view s)
{
	s.remove_prefix(std::min(s.find_first_not_of(" \t\r\v\n"), s.size()));
	s.remove_suffix(std::min(s.size() - s.find_last_not_of(" \t\r\v\n") - 1, s.size()));
	
	return s;
}

A nice alternative:

std::string_view ltrim(std::string_view s)
{
	s.remove_prefix(std::distance(s.cbegin(), std::find_if(s.cbegin(), s.cend(),
		 [](int c) {return !std::isspace(c);})));

	return s;
}

std::string_view rtrim(std::string_view s)
{
	s.remove_suffix(std::distance(s.crbegin(), std::find_if(s.crbegin(), s.crend(),
		[](int c) {return !std::isspace(c);})));

	return s;
}

std::string_view trim(std::string_view s)
{
	return ltrim(rtrim(s));
}

Solution 10 - C++

In the case of an empty string, your code assumes that adding 1 to string::npos gives 0. string::npos is of type string::size_type, which is unsigned. Thus, you are relying on the overflow behaviour of addition.

Solution 11 - C++

Hacked off of Cplusplus.com

std::string choppa(const std::string &t, const std::string &ws)
{
	std::string str = t;
    size_t found;
	found = str.find_last_not_of(ws);
	if (found != std::string::npos)
		str.erase(found+1);
	else
		str.clear();            // str is all whitespace

	return str;
}

This works for the null case as well. :-)

Solution 12 - C++

s.erase(0, s.find_first_not_of(" \n\r\t"));                                                                                               
s.erase(s.find_last_not_of(" \n\r\t")+1);   

                                                                                      

Solution 13 - C++

My solution based on the answer by @Bill the Lizard.

Note that these functions will return the empty string if the input string contains nothing but whitespace.

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

std::string StringUtils::Trim(const std::string& s)
{
    return TrimRight(TrimLeft(s));
}

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

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

Solution 14 - C++

With C++11 also came a regular expression module, which of course can be used to trim leading or trailing spaces.

Maybe something like this:

std::string ltrim(const std::string& s)
{
	static const std::regex lws{"^[[:space:]]*", std::regex_constants::extended};
	return std::regex_replace(s, lws, "");
}

std::string rtrim(const std::string& s)
{
	static const std::regex tws{"[[:space:]]*$", std::regex_constants::extended};
	return std::regex_replace(s, tws, "");
}

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

Solution 15 - C++

My answer is an improvement upon the top answer for this post that trims control characters as well as spaces (0-32 and 127 on the ASCII table).

std::isgraph determines if a character has a graphical representation, so you can use this to alter Evan's answer to remove any character that doesn't have a graphical representation from either side of a string. The result is a much more elegant solution:

#include <algorithm>
#include <functional>
#include <string>

/**
 * @brief Left Trim
 *
 * Trims whitespace from the left end of the provided std::string
 *
 * @param[out] s The std::string to trim
 *
 * @return The modified std::string&
 */
std::string& ltrim(std::string& s) {
  s.erase(s.begin(), std::find_if(s.begin(), s.end(),
    std::ptr_fun<int, int>(std::isgraph)));
  return s;
}

/**
 * @brief Right Trim
 *
 * Trims whitespace from the right end of the provided std::string
 *
 * @param[out] s The std::string to trim
 *
 * @return The modified std::string&
 */
std::string& rtrim(std::string& s) {
  s.erase(std::find_if(s.rbegin(), s.rend(),
    std::ptr_fun<int, int>(std::isgraph)).base(), s.end());
  return s;
}

/**
 * @brief Trim
 *
 * Trims whitespace from both ends of the provided std::string
 *
 * @param[out] s The std::string to trim
 *
 * @return The modified std::string&
 */
std::string& trim(std::string& s) {
  return ltrim(rtrim(s));
}

Note: Alternatively you should be able to use std::iswgraph if you need support for wide characters, but you will also have to edit this code to enable std::wstring manipulation, which is something that I haven't tested (see the reference page for std::basic_string to explore this option).

Solution 16 - C++

This is what I use. Just keep removing space from the front, and then, if there's anything left, do the same from the back.

void trim(string& s) {
	while(s.compare(0,1," ")==0)
		s.erase(s.begin()); // remove leading whitespaces
	while(s.size()>0 && s.compare(s.size()-1,1," ")==0)
		s.erase(s.end()-1); // remove trailing whitespaces
}

Solution 17 - C++

An elegant way of doing it can be like

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

And the supportive functions are implemented as:

std::string & ltrim(std::string & str)
{
  auto it =  std::find_if( str.begin() , str.end() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
  str.erase( str.begin() , it);
  return str;   
}

std::string & rtrim(std::string & str)
{
  auto it =  std::find_if( str.rbegin() , str.rend() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
  str.erase( it.base() , str.end() );
  return str;   
}

And once you've all these in place, you can write this as well:

std::string trim_copy(std::string const & str)
{
   auto s = str;
   return ltrim(rtrim(s));
}

Solution 18 - C++

For what it's worth, here is a trim implementation with an eye towards performance. It's much quicker than many other trim routines I've seen around. Instead of using iterators and std::finds, it uses raw c strings and indices. It optimizes the following special cases: size 0 string (do nothing), string with no whitespace to trim (do nothing), string with only trailing whitespace to trim (just resize the string), string that's entirely whitespace (just clear the string). And finally, in the worst case (string with leading whitespace), it does its best to perform an efficient copy construction, performing only 1 copy and then moving that copy in place of the original string.

void TrimString(std::string & str)
{ 
    if(str.empty())
        return;

    const auto pStr = str.c_str();

    size_t front = 0;
    while(front < str.length() && std::isspace(int(pStr[front]))) {++front;}

    size_t back = str.length();
    while(back > front && std::isspace(int(pStr[back-1]))) {--back;}

    if(0 == front)
    {
        if(back < str.length())
        {
            str.resize(back - front);
        }
    }
    else if(back <= front)
    {
        str.clear();
    }
    else
    {
        str = std::move(std::string(str.begin()+front, str.begin()+back));
    }
}

Solution 19 - C++

Here is a solution for trim with regex

#include <string>
#include <regex>

string trim(string str){
    return regex_replace(str, regex("(^[ ]+)|([ ]+$)"),"");
}

Solution 20 - C++

I guess if you start asking for the "best way" to trim a string, I'd say a good implementation would be one that:

  1. Doesn't allocate temporary strings
  2. Has overloads for in-place trim and copy trim
  3. Can be easily customized to accept different validation sequences / logic

Obviously there are too many different ways to approach this and it definitely depends on what you actually need. However, the C standard library still has some very useful functions in <string.h>, like memchr. There's a reason why C is still regarded as the best language for IO - its stdlib is pure efficiency.

inline const char* trim_start(const char* str)
{
	while (memchr(" \t\n\r", *str, 4))	++str;
	return str;
}
inline const char* trim_end(const char* end)
{
	while (memchr(" \t\n\r", end[-1], 4)) --end;
	return end;
}
inline std::string trim(const char* buffer, int len) // trim a buffer (input?)
{
	return std::string(trim_start(buffer), trim_end(buffer + len));
}
inline void trim_inplace(std::string& str)
{
	str.assign(trim_start(str.c_str()),
		trim_end(str.c_str() + str.length()));
}

int main()
{
	char str [] = "\t \nhello\r \t \n";

	string trimmed = trim(str, strlen(str));
	cout << "'" << trimmed << "'" << endl;

	system("pause");
	return 0;
}

Solution 21 - C++

Trim C++11 implementation:

static void trim(std::string &s) {
     s.erase(s.begin(), std::find_if_not(s.begin(), s.end(), [](char c){ return std::isspace(c); }));
     s.erase(std::find_if_not(s.rbegin(), s.rend(), [](char c){ return std::isspace(c); }).base(), s.end());
}

Solution 22 - C++

Contributing my solution to the noise. trim defaults to creating a new string and returning the modified one while trim_in_place modifies the string passed to it. The trim function supports c++11 move semantics.

#include <string>

// modifies input string, returns input

std::string& trim_left_in_place(std::string& str) {
	size_t i = 0;
	while(i < str.size() && isspace(str[i])) { ++i; };
	return str.erase(0, i);
}

std::string& trim_right_in_place(std::string& str) {
	size_t i = str.size();
	while(i > 0 && isspace(str[i - 1])) { --i; };
	return str.erase(i, str.size());
}

std::string& trim_in_place(std::string& str) {
	return trim_left_in_place(trim_right_in_place(str));
}

// returns newly created strings

std::string trim_right(std::string str) {
	return trim_right_in_place(str);
}

std::string trim_left(std::string str) {
	return trim_left_in_place(str);
}

std::string trim(std::string str) {
	return trim_left_in_place(trim_right_in_place(str));
}

#include <cassert>

int main() {

	std::string s1(" \t\r\n  ");
	std::string s2("  \r\nc");
	std::string s3("c \t");
	std::string s4("  \rc ");

	assert(trim(s1) == "");
	assert(trim(s2) == "c");
	assert(trim(s3) == "c");
	assert(trim(s4) == "c");

	assert(s1 == " \t\r\n  ");
	assert(s2 == "  \r\nc");
	assert(s3 == "c \t");
	assert(s4 == "  \rc ");

	assert(trim_in_place(s1) == "");
	assert(trim_in_place(s2) == "c");
	assert(trim_in_place(s3) == "c");
	assert(trim_in_place(s4) == "c");

	assert(s1 == "");
	assert(s2 == "c");
	assert(s3 == "c");
	assert(s4 == "c");	
}

Solution 23 - C++

str.erase(0, str.find_first_not_of("\t\n\v\f\r ")); // left trim
str.erase(str.find_last_not_of("\t\n\v\f\r ") + 1); // right trim

Solution 24 - C++

This can be done more simply in C++11 due to the addition of back() and pop_back().

while ( !s.empty() && isspace(s.back()) ) s.pop_back();

Solution 25 - C++

I'm not sure if your environment is the same, but in mine, the empty string case will cause the program to abort. I would either wrap that erase call with an if(!s.empty()) or use Boost as already mentioned.

Solution 26 - C++

Here's what I came up with:

std::stringstream trimmer;
trimmer << str;
trimmer >> str;

Stream extraction eliminates whitespace automatically, so this works like a charm.
Pretty clean and elegant too, if I do say so myself. ;)

Solution 27 - C++

Here is my version:

size_t beg = s.find_first_not_of(" \r\n");
return (beg == string::npos) ? "" : in.substr(beg, s.find_last_not_of(" \r\n") - beg);

Solution 28 - C++

Here's a solution easy to understand for beginners not used to write std:: everywhere and not yet familiar with const-correctness, iterators, STL algorithms, etc...

#include <string>
#include <cctype> // for isspace
using namespace std;


// Left trim the given string ("  hello!  " --> "hello!  ")
string left_trim(string str) {
	int numStartSpaces = 0;
	for (int i = 0; i < str.length(); i++) {
		if (!isspace(str[i])) break;
		numStartSpaces++;
	}
	return str.substr(numStartSpaces);
}

// Right trim the given string ("  hello!  " --> "  hello!")
string right_trim(string str) {
	int numEndSpaces = 0;
	for (int i = str.length() - 1; i >= 0; i--) {
		if (!isspace(str[i])) break;
		numEndSpaces++;
	}
	return str.substr(0, str.length() - numEndSpaces);
}

// Left and right trim the given string ("  hello!  " --> "hello!")
string trim(string str) {
	return right_trim(left_trim(str));
}

Hope it helps...

Solution 29 - C++

The above methods are great, but sometimes you want to use a combination of functions for what your routine considers to be whitespace. In this case, using functors to combine operations can get messy so I prefer a simple loop I can modify for the trim. Here is a slightly modified trim function copied from the C version here on SO. In this example, I am trimming non alphanumeric characters.

string trim(char const *str)
{
  // Trim leading non-letters
  while(!isalnum(*str)) str++;

  // Trim trailing non-letters
  end = str + strlen(str) - 1;
  while(end > str && !isalnum(*end)) end--;

  return string(str, end+1);
}

Solution 30 - C++

What about this...?

#include <iostream>
#include <string>
#include <regex>

std::string ltrim( std::string str ) {
	return std::regex_replace( str, std::regex("^\\s+"), std::string("") );
}

std::string rtrim( std::string str ) {
	return std::regex_replace( str, std::regex("\\s+$"), std::string("") );
}

std::string trim( std::string str ) {
	return ltrim( rtrim( str ) );
}

int main() {

	std::string str = "   \t  this is a test string  \n   ";
	std::cout << "-" << trim( str ) << "-\n";
	return 0;

}

Note: I'm still relatively new to C++, so please forgive me if I'm off base here.

Solution 31 - C++

Here is a straight forward implementation. For such a simple operation, you probably should not be using any special constructs. The build-in isspace() function takes care of various forms of white characters, so we should take advantage of it. You also have to consider special cases where the string is empty or simply a bunch of spaces. Trim left or right could be derived from the following code.

string trimSpace(const string &str) {
   if (str.empty()) return str;
   string::size_type i,j;
   i=0;
   while (i<str.size() && isspace(str[i])) ++i;
   if (i == str.size())
      return string(); // empty string
   j = str.size() - 1;
   //while (j>0 && isspace(str[j])) --j; // the j>0 check is not needed
   while (isspace(str[j])) --j
   return str.substr(i, j-i+1);
}

Solution 32 - C++

This version trims internal whitespace and non-alphanumerics:

static inline std::string &trimAll(std::string &s)
{   
    if(s.size() == 0)
    {
        return s;
    }

    int val = 0;
    for (int cur = 0; cur < s.size(); cur++)
    {
        if(s[cur] != ' ' && std::isalnum(s[cur]))
        {
            s[val] = s[cur];
            val++;
        }
    }
    s.resize(val);
    return s;
}

Solution 33 - C++

Yet another option - removes one or more characters from both ends.

string strip(const string& s, const string& chars=" ") {
    size_t begin = 0;
    size_t end = s.size()-1;
    for(; begin < s.size(); begin++)
        if(chars.find_first_of(s[begin]) == string::npos)
            break;
    for(; end > begin; end--)
        if(chars.find_first_of(s[end]) == string::npos)
            break;
    return s.substr(begin, end-begin+1);
}

Solution 34 - C++

As I wanted to update my old C++ trim function with a C++ 11 approach I have tested a lot of the posted answers to the question. My conclusion is that I keep my old C++ solution!

It is the fastest one by large, even adding more characters to check (e.g. \r\n I see no use case for \f\v) is still faster than the solutions using algorithm.

std::string & trimMe (std::string & str)
{
   // right trim
   while (str.length () > 0 && (str [str.length ()-1] == ' ' || str [str.length ()-1] == '\t'))
      str.erase (str.length ()-1, 1);
     
   // left trim
   while (str.length () > 0 && (str [0] == ' ' || str [0] == '\t'))
      str.erase (0, 1);
   return str;
}

Solution 35 - C++

Ok this maight not be the fastest but it's... simple.

str = "   aaa    ";
int len = str.length();
// rtrim
while(str[len-1] == ' ') { str.erase(--len,1); }
// ltrim
while(str[0] == ' ') { str.erase(0,1); }

Solution 36 - C++

std::string trim( std::string && str )
{
    size_t end = str.find_last_not_of( " \n\r\t" );
    if ( end != std::string::npos )
        str.resize( end + 1 );

    size_t start = str.find_first_not_of( " \n\r\t" );
    if ( start != std::string::npos )
        str = str.substr( start );

    return std::move( str );
}

Solution 37 - C++

This any good? (Cause this post totally needs another answer :)

string trimBegin(string str)
{
    string whites = "\t\r\n ";
    int i = 0;
    while (whites.find(str[i++]) != whites::npos);
    str.erase(0, i);
    return str;
}

Similar case for the trimEnd, just reverse the polari- er, indices.

Solution 38 - C++

I'm using this one:

void trim(string &str){
    int i=0;

    //left trim
    while (isspace(str[i])!=0)
        i++;
    str = str.substr(i,str.length()-i);

    //right trim
    i=str.length()-1;
    while (isspace(str[i])!=0)
        i--;
    str = str.substr(0,i+1);
}

Solution 39 - C++

c++11:

int i{};
string s = " h e ll \t\n  o";
string trim = " \n\t";
    
while ((i = s.find_first_of(trim)) != -1)
   	s.erase(i,1);

cout << s;

output:

hello

works fine also with empty strings

Solution 40 - C++

I know this is a very old question, but I have added a few lines of code to yours and it trims whitespace from both ends.

void trim(std::string &line){

    auto val = line.find_last_not_of(" \n\r\t") + 1;

    if(val == line.size() || val == std::string::npos){
	    val = line.find_first_not_of(" \n\r\t");
	    line = line.substr(val);
    }
    else
	    line.erase(val);
}

Solution 41 - C++

Below is one pass(may be two pass) solution. It goes over the white spaces part of string twice and non-whitespace part once.

void trim(std::string& s) {                                                                                                                                                                                                               
    if (s.empty())                                                                                                                                                                                                                        
        return;                                                                                                                                                                                                                           
                                                                                                                                                                                                                                          
    int l = 0, r = s.size()  - 1;                                                                                                                                                                                                         
                                                                                                                                                                                                                                          
    while (l < s.size() && std::isspace(s[l++])); // l points to first non-whitespace char.                                                                                                                                               
    while (r >= 0 && std::isspace(s[r--])); // r points to last non-whitespace char.                                                                                                                                                      
                                                                                                                                                                                                                                          
    if (l > r)                                                                                                                                                                                                                            
        s = "";                                                                                                                                                                                                                           
    else {                                                                                                                                                                                                                                
        l--;                                                                                                                                                                                                                              
        r++;                                                                                                                                                                                                                              
        int wi = 0;                                                                                                                                                                                                                       
        while (l <= r)                                                                                                                                                                                                                    
            s[wi++] = s[l++];                                                                                                                                                                                                             
        s.erase(wi);                                                                                                                                                                                                                      
    }                                                                                                                                                                                                                                     
    return;                                                                                                                                                                                                                               
}                                          

Solution 42 - C++

The accepted answer and even Boost's version did not work for me, so I wrote the following version:

std::string trim(const std::string& input) {
	std::stringstream string_stream;
	for (const auto character : input) {
		if (!isspace(character)) {
			string_stream << character;
		}
	}

	return string_stream.str();
}

This will remove any whitespace character from anywhere in the string and return a new copy of the string.

Solution 43 - C++

I have read most of the answers but did not found anyone making use of istringstream

std::string text = "Let me split this into words";

std::istringstream iss(text);
std::vector<std::string> results((std::istream_iterator<std::string>(iss)),
                                 std::istream_iterator<std::string>());

The result is vector of words and it can deal with the strings having internal whitespace too, Hope this helped.

Solution 44 - C++

why not use lambda?

auto no_space = [](char ch) -> bool {
  return !std::isspace<char>(ch, std::locale::classic());
};
auto ltrim = [](std::string& s) -> std::string& {
  s.erase(s.begin(), std::find_if(s.begin(), s.end(), no_space));
  return s;
};
auto rtrim = [](std::string& s) -> std::string& {
  s.erase(std::find_if(s.rbegin(), s.rend(), no_space).base(), s.end());
  return s;
};
auto trim_copy = [](std::string s) -> std::string& { return ltrim(rtrim(s)); };
auto trim = [](std::string& s) -> std::string& { return ltrim(rtrim(s)); };

Solution 45 - C++

Trims both ends.

string trim(const std::string &str){
    string result = "";
    size_t endIndex = str.size();
    while (endIndex > 0 && isblank(str[endIndex-1]))
        endIndex -= 1;
    for (size_t i=0; i<endIndex ; i+=1){
        char ch = str[i];
        if (!isblank(ch) || result.size()>0)
            result += ch;
    }
   return result;
}

Solution 46 - C++

Poor man's string trim (spaces only):

std::string trimSpaces(const std::string& str)
{
    int start, len;
    
    for (start = 0; start < str.size() && str[start] == ' '; start++);
    for (len = str.size() - start; len > 0 && str[start + len - 1] == ' '; len--);
    
    return str.substr(start, len);
}

Solution 47 - C++

It seems I'm really late to the party - I can't believe this was asked 7 years ago!

Here's my take on the problem. I'm working on a project and I didn't want to go through the trouble of using Boost right now.

std::string trim(std::string str) {
    if(str.length() == 0) return str;

    int beg = 0, end = str.length() - 1;
    while (str[beg] == ' ') {
	    beg++;
    }

    while (str[end] == ' ') {
	    end--;
    }

    return str.substr(beg, end - beg + 1);
}

This solution will trim from the left and the right.

Solution 48 - C++

It is so annoying that I

  • have to google it
  • find out that I have to use rocket science
  • that there is no simple trim/toupper function in string

For me this is the fastest way to solve it:

CString tmp(line.c_str());
tmp = tmp.Trim().MakeLower();
string buffer = tmp;

Ok, it is cool that I can use lambda ops, iterators, and all the stuff. But I only need to deal with a string instead of a character...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMilan BabuškovView Question on Stackoverflow
Solution 1 - C++Evan TeranView Answer on Stackoverflow
Solution 2 - C++Leon TimmermansView Answer on Stackoverflow
Solution 3 - C++GalikView Answer on Stackoverflow
Solution 4 - C++Bill the LizardView Answer on Stackoverflow
Solution 5 - C++David GView Answer on Stackoverflow
Solution 6 - C++user818330View Answer on Stackoverflow
Solution 7 - C++PushkoffView Answer on Stackoverflow
Solution 8 - C++Michaël SchoonbroodView Answer on Stackoverflow
Solution 9 - C++PhideluxView Answer on Stackoverflow
Solution 10 - C++Greg HewgillView Answer on Stackoverflow
Solution 11 - C++Paul NathanView Answer on Stackoverflow
Solution 12 - C++freeboy1015View Answer on Stackoverflow
Solution 13 - C++DavidRRView Answer on Stackoverflow
Solution 14 - C++Some programmer dudeView Answer on Stackoverflow
Solution 15 - C++Clay FreemanView Answer on Stackoverflow
Solution 16 - C++synaptikView Answer on Stackoverflow
Solution 17 - C++jha-GView Answer on Stackoverflow
Solution 18 - C++mbgdaView Answer on Stackoverflow
Solution 19 - C++Sadidul IslamView Answer on Stackoverflow
Solution 20 - C++Jorma RebaneView Answer on Stackoverflow
Solution 21 - C++GutiMacView Answer on Stackoverflow
Solution 22 - C++vmrobView Answer on Stackoverflow
Solution 23 - C++ArtyView Answer on Stackoverflow
Solution 24 - C++Brent BradburnView Answer on Stackoverflow
Solution 25 - C++SteveView Answer on Stackoverflow
Solution 26 - C++tzamanView Answer on Stackoverflow
Solution 27 - C++nulleightView Answer on Stackoverflow
Solution 28 - C++cute_ptrView Answer on Stackoverflow
Solution 29 - C++Corwin JoyView Answer on Stackoverflow
Solution 30 - C++DuncanView Answer on Stackoverflow
Solution 31 - C++Kemin ZhouView Answer on Stackoverflow
Solution 32 - C++BrianView Answer on Stackoverflow
Solution 33 - C++Brian W.View Answer on Stackoverflow
Solution 34 - C++elxalaView Answer on Stackoverflow
Solution 35 - C++JacktView Answer on Stackoverflow
Solution 36 - C++Alexander DrichelView Answer on Stackoverflow
Solution 37 - C++BondolinView Answer on Stackoverflow
Solution 38 - C++FloellaView Answer on Stackoverflow
Solution 39 - C++user1438233View Answer on Stackoverflow
Solution 40 - C++user3229557View Answer on Stackoverflow
Solution 41 - C++UnSatView Answer on Stackoverflow
Solution 42 - C++BullyWiiPlazaView Answer on Stackoverflow
Solution 43 - C++Anil GuptaView Answer on Stackoverflow
Solution 44 - C++antb52View Answer on Stackoverflow
Solution 45 - C++ragnariusView Answer on Stackoverflow
Solution 46 - C++MatthiasView Answer on Stackoverflow
Solution 47 - C++Developer Formerly Known as VView Answer on Stackoverflow
Solution 48 - C++SlesaView Answer on Stackoverflow