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

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

它工作得很好,但我想知道是否有一些最终情况下它可能会失败?

当然,有优雅的选择和左修剪解决方案的答案是受欢迎的。


当前回答

我认为在这个例子中使用宏是一个很好的实践:(适用于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::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 );
}

下面是一个简单的实现。对于这样一个简单的操作,您可能不应该使用任何特殊的构造。内置的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 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);
}

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

#include <boost/algorithm/string.hpp>

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

STR现在是"hello world!"。还有trim_left和trim,它们修剪两边。


如果你给上面的函数名加上_copy后缀,例如trim_copy,函数将返回一个经过修剪的字符串副本,而不是通过引用修改它。

如果你给上面的任何函数名加上_if后缀,例如trim_copy_if,你可以修剪所有满足自定义谓词的字符,而不是只有空白。

一种优雅的方法可以是

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

我已经阅读了大部分答案,但没有发现任何人使用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>());

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