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

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

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

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


当前回答

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

其他回答

我知道这是一个非常老的问题,但我已经为您的问题添加了几行代码,它从两端删除了空白。

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

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

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

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

为什么不用?

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