For C++11
#include <algorithm> #include <cctype> #include <locale> // Trim from the start (in place) 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 the end (in place) 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()); }
Thanks to std::ptr_fun replacement for c++17 for bringing up the modern solution.
Convenience functions
// Trim from both ends (in place) inline void trim(std::string &s) { rtrim(s); ltrim(s); } // Trim from the start (copying) inline std::string ltrim_copy(std::string s) { ltrim(s); return s; } // Trim from the end (copying) inline std::string rtrim_copy(std::string s) { rtrim(s); return s; } // Trim from both ends (copying) inline std::string trim_copy(std::string s) { trim(s); return s; }
For C++03
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 the start (in place) 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 the end (in place) 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()); } // The remaining functions (trim() et al.) are identical to the new C++11 version
std::ptr_fun is needed to disambiguate std::isspace because there is a second definition which supports locales. This could have been a cast just the same, but I tend to like this better.
Another answer for C++03
#include <algorithm> #include <functional> #include <cctype> #include <locale> // Trim from start inline std::string <rim(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 the end 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 inline std::string &trim(std::string &s) { return ltrim(rtrim(s)); }