如何修剪d::弦?

我目前正在使用以下代码来右修剪我的程序中的所有std::strings

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

它运行良好,但我想知道是否有一些最终情况下它可能会失败?

当然,与优雅的替代品和左修剪解决方案的答案是受欢迎的。

903131 次浏览

在空字符串的情况下,您的代码假设将1添加到string::npos会得到0。string::npos的类型为string::size_type,是无符号的。因此,您依赖于加法的溢出行为。

使用Boost的字符串算法将是最简单的:

#include <boost/algorithm/string.hpp>
std::string str("hello world! ");boost::trim_right(str);

str现在是"hello world!"。还有trim_lefttrim,它们修剪了两边。


如果您将_copy后缀添加到上述任何函数名称,例如trim_copy,该函数将返回字符串的修剪副本,而不是通过引用修改它。

如果将_if后缀添加到上述任何函数名称(例如trim_copy_if),则可以修剪满足自定义谓词的所有字符,而不仅仅是空格。

我不确定您的环境是否相同,但在我的环境中,空字符串情况将导致程序中止。我要么用if(!s.empty())包装该erase调用,要么使用前面提到的Boost。

删除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);elsestr.clear();            // str is all whitespace
return str;}

这也适用于空情况。:-)

编辑从c++17开始,标准库的某些部分被删除了。幸运的是,从c++11开始,我们有了lambda,这是一个更好的解决方案。

#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) {rtrim(s);ltrim(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;}

感谢https://stackoverflow.com/a/44973498/524503提出了现代解决方案。

原答复:

我倾向于使用这3个中的一个来满足我的修剪需求:

#include <algorithm>#include <functional>#include <cctype>#include <locale>
// trim from startstatic 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 endstatic 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 endsstatic inline std::string &trim(std::string &s) {return ltrim(rtrim(s));}

它们相当不言自明,工作得很好。

编辑:顺便说一句,我在那里有std::ptr_fun来帮助消除std::isspace的歧义,因为实际上有第二个支持语言环境的定义。这可能是一个相同的演员,但我更喜欢这个。

编辑:解决一些关于通过引用接受参数、修改和返回参数的评论。我同意。我可能更喜欢的实现是两组函数,一组用于就地,一组用于复制。一组更好的例子是:

#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) {rtrim(s);ltrim(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;}

我保留了上面的原始答案,尽管是为了上下文,也是为了保持高投票率的答案仍然可用。

使用以下代码从std::stringsideone)向右修剪(尾随)空格和制表符:

// trim trailing spacessize_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));}

为了平衡,我也将包含左侧修剪代码(ideone):

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

上面的方法很棒,但是有时你想为你的例程认为是空格的东西使用函数的组合。在这种情况下,使用函数来组合操作可能会变得混乱,所以我更喜欢一个简单的循环,我可以修改修剪。这是一个稍微修改的修剪函数,从SO上的C版本复制。在这个例子中,我正在修剪非字母数字字符。

string trim(char const *str){// Trim leading non-letterswhile(!isalnum(*str)) str++;
// Trim trailing non-lettersend = str + strlen(str) - 1;while(end > str && !isalnum(*end)) end--;
return string(str, end+1);}

这是我想出的:

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

流提取会自动消除空格,所以这就像一个魅力。
很干净,也很优雅,如果我自己这么说的话;)

我喜欢tzaman的解决方案,唯一的问题是它不会修剪只包含空格的字符串。

要纠正该1缺陷,请在2个修剪线之间添加str.clear()

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

此版本修剪了内部空格和非字母数字:

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;}

试试这个,它对我有用。

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

另一个选项-从两端删除一个或多个字符。

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);}

我的解决方案基于作者:比尔蜥蜴

请注意,如果输入字符串只包含空格,这些函数将返回空字符串。

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);}

派对有点晚了,但没关系。现在C++11在这里,我们有lambda和自动变量。所以我的版本,也处理全空格和空字符串,是:

#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));}

我们可以从wsfront创建一个反向迭代器,并将其用作第二个find_if_not中的终止条件,但这只在全空格字符串的情况下有用,而且gcc 4.8至少还不够聪明,无法推断auto的反向迭代器(std::string::const_reverse_iterator)的类型。我不知道构建一个反向迭代器有多昂贵,所以YMMV在这里。通过这个修改,代码看起来像这样:

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());}

C++11还带来了一个正则表达式模块,当然可以用来修剪前导或尾随空间。

也许像这样:

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));}

这个怎么样…?

#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;
}

注意:我对C++还比较陌生,所以如果我在这里偏离了基础,请原谅我。

这是我用的方法。只要不断地从前面移开空间,然后,如果还有剩余的东西,从后面做同样的事情。

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

我想如果你开始问修剪字符串的“最佳方式”,我会说一个好的实现是:

  1. 不分配临时字符串
  2. 具有用于就地修剪和复制修剪的重载
  3. 可以轻松定制以接受不同的验证序列/逻辑

显然,有太多不同的方法来解决这个问题,这绝对取决于你实际需要什么。然而,C标准库在中仍然有一些非常有用的功能,比如memchr。C仍然被认为是IO的最佳语言是有原因的——它的stdlib纯粹是效率。

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;}
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 );}

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());}

这有什么好处吗?(因为这篇文章完全需要另一个答案:)

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;}

类似的情况下trimEnd,只是扭转极性,指数。

trim默认创建一个新字符串并返回修改后的字符串,而trim_in_place修改传递给它的字符串。trim函数支持c++11移动语义学。

#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");}

你正在做的事情很好而且很稳健。我已经使用了很长时间的相同方法,但我还没有找到更快的方法:

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);}

通过提供要修剪的字符,您可以灵活地修剪非空白字符,并且可以高效地仅修剪您想要修剪的字符。

不管怎样,这是一个关注性能的修剪实现。它比我见过的许多其他修剪例程要快得多。它不使用迭代器和std::finds,而是使用原始c字符串和索引。它优化了以下特殊情况:大小为0的字符串(什么都不做)、没有空格要修剪的字符串(什么都不做)、只有尾随空格要修剪的字符串(只需调整字符串大小)、完全是空格的字符串(只需清除字符串)。最后,在最坏的情况下(带有前导空格的字符串),它尽最大努力执行高效的副本构造,只执行1个副本,然后将该副本移动到原始字符串的位置。

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));}}

我的答案是对这篇文章的最高答案的改进,它修剪了控制字符和空格(ascii表上的0-32和127)。

std::isgraph确定字符是否具有图形表示,因此您可以使用它来更改Evan的答案,以删除字符串两侧没有图形表示的任何字符。结果是一个更优雅的解决方案:

#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));}

备注:或者,如果您需要支持宽字符,您应该能够使用std::iswgraph,但您还必须编辑此代码以启用std::wstring操作,这是我没有测试过的(请参阅std::basic_string的参考页面以探索此选项)。

优雅的做法可以是

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

支持功能的实现方式是:

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;}

一旦你完成了所有这些,你也可以这样写:

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

我正在使用这个:

void trim(string &str){int i=0;
//left trimwhile (isspace(str[i])!=0)i++;str = str.substr(i,str.length()-i);
//right trimi=str.length()-1;while (isspace(str[i])!=0)i--;str = str.substr(0,i+1);}
s.erase(0, s.find_first_not_of(" \n\r\t"));s.erase(s.find_last_not_of(" \n\r\t")+1);

TrimC++11实现:

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());}

看来我真的迟到了——我不敢相信这是7年前被问到的!

这是我对这个问题的看法。我正在做一个项目,我现在不想经历使用Boost的麻烦。

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);}

该解决方案将从左侧和右侧修剪。

由于添加了back()pop_back(),这可以在C++11中更简单地完成。

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

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;

输出:

hello

空字符串也能正常工作

当我想用C++方法更新我的旧C++修剪函数时,我已经测试了很多发布的问题答案。我的结论是,我保留了我的旧C++解决方案!

总的来说,它是最快的,即使添加更多的字符来检查(例如\r\n我没有看到\f\v的用例)仍然比使用算法的解决方案更快。

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

这是一个直截了当的实现。对于这样一个简单的操作,你可能不应该使用任何特殊的构造。内置的isspace()函数负责处理各种形式的白色字符,所以我们应该利用它。你还必须考虑字符串为空或只是一堆空格的特殊情况。向左或向右修剪可以从以下代码派生。

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 stringj = str.size() - 1;//while (j>0 && isspace(str[j])) --j; // the j>0 check is not neededwhile (isspace(str[j])) --jreturn str.substr(i, j-i+1);}

以下是我的版本:

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);

这里有一个易于理解的解决方案,对于不习惯到处写std::并且还不熟悉const-正确性、iterators、STLalgorithms等的初学者来说…

#include <string>#include <cctype> // for isspaceusing 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));}

希望它能帮助…

这太烦人了,我

  • 得谷歌一下
  • 发现我得用火箭科学
  • 字符串中没有简单的trim/Toupper函数

对于,这是解决它的最快方法:

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

好的,我可以使用lambda操作、迭代器和所有东西,这很酷。但我只需要处理字符串而不是字符……

我知道这是一个非常古老的问题,但我已经为你添加了几行代码,它从两端修剪了空格。

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);}elseline.erase(val);}

下面是一个通过(可能是两个通过)的解决方案。它遍历字符串的空格部分两次,非空格部分一次。

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;}

使用C++17,您可以使用basic_string_view::remove_prefixbasic_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;}

一个不错的选择:

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));}

好吧,这不是最快的,但它是……简单。

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

这是一个用regex修剪的解决方案

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

接受的答案,甚至Boost的版本都不适合我,所以我写了以下版本:

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();}

这将从字符串中的任何位置删除任何空格字符并返回字符串的新副本。

我已经阅读了大部分的答案,但没有发现任何人使用stringstream

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>());

结果是单词向量,它也可以处理具有内部空格的字符串,希望这有帮助。

为什么不使用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)); };

修剪两端。

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;}
str.erase(0, str.find_first_not_of("\t\n\v\f\r ")); // left trimstr.erase(str.find_last_not_of("\t\n\v\f\r ") + 1); // right trim

试试在线!

穷人的绳子修剪(仅限空格):

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);}

你可以用这个函数修剪你的弦c++

void trim(string& str){while(str[0] == ' ') str.erase(str.begin());while(str[str.size() - 1] == ' ') str.pop_back();}

我认为在这个例子中使用宏是一个很好的做法:(适用于C++98)

#define TRIM_CHARACTERS " \t\n\r\f\v"#define TRIM_STRING(given) \given.erase(given.find_last_not_of(TRIM_CHARACTERS) + 1); \given.erase(0, given.find_first_not_of(TRIM_CHARACTERS));

例子:

#include <iostream>#include <string>
#define TRIM_CHARACTERS " \t\n\r\f\v"#define TRIM_STRING(given) \given.erase(given.find_last_not_of(TRIM_CHARACTERS) + 1); \given.erase(0, given.find_first_not_of(TRIM_CHARACTERS));
int main(void) {std::string text("  hello world!! \t  \r");TRIM_STRING(text);std::cout << text; // "hello world!!"}

使用std::find_if_not和反向迭代器(无+1/-1调整)并返回修剪的空格数

// returns number of spaces removedstd::size_t RoundTrim(std::string& s){auto const beforeTrim{ s.size() };
auto isSpace{ [](auto const& e) { return std::isspace(e); } };
s.erase(cbegin(s), std::find_if_not(cbegin(s), cend(s), isSpace));s.erase(std::find_if_not(crbegin(s), crend(s), isSpace).base(), end(s));
return beforeTrim - s.size();};