935

我目前正在使用以下代码对std::strings我的程序中的所有内容进行右修剪:

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

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

当然,欢迎使用优雅的替代方案和左修剪解决方案的答案。

4

48 回答 48

769

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

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

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

原答案:

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

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

它们是不言自明的并且工作得很好。

编辑:顺便说一句,我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) {
    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;
}

我保留了上面的原始答案,但为了上下文和保持高票答案仍然可用。

于 2008-10-20T05:46:38.777 回答
447

使用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,您可以修剪所有满足您的自定义谓词的字符,而不仅仅是空格。

于 2008-10-19T19:55:06.820 回答
77

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

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

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

于 2014-08-19T14:16:58.527 回答
63

使用以下代码从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));
}

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

// trim leading spaces
size_t startpos = str.find_first_not_of(" \t");
if( string::npos != startpos )
{
    str = str.substr( startpos );
}
于 2008-12-07T19:45:40.250 回答
60

派对迟到了,但没关系。现在 C++11 来了,我们有 lambdas 和 auto 变量。所以我的版本,它也处理全空格和空字符串,是:

#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 至少不够聪明,无法推断反向迭代器的类型(std::string::const_reverse_iterator) 与auto. 我不知道构建反向迭代器有多昂贵,所以这里是 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());
}
于 2013-07-31T17:03:12.047 回答
58

试试这个,它对我有用。

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;
}
于 2011-06-28T00:47:53.440 回答
27

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

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

std::stringstream trimmer;
trimmer << str;
str.clear();
trimmer >> str;
于 2010-07-05T06:37:20.050 回答
27

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());
}
于 2014-02-11T10:15:06.107 回答
23

使用 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));
}
于 2019-01-25T11:13:02.680 回答
19

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

于 2008-10-19T19:26:43.850 回答
13

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

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

于 2008-10-19T20:47:47.057 回答
12
s.erase(0, s.find_first_not_of(" \n\r\t"));                                                                                               
s.erase(s.find_last_not_of(" \n\r\t")+1);   
于 2015-10-13T10:02:16.440 回答
11

我的解决方案基于@Bill the Lizard 的回答

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

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);
}
于 2013-05-24T21:11:22.080 回答
9

我的答案是对这篇文章的最佳答案的改进,它修剪了控制字符和空格( 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以探索此选项) .

于 2015-03-21T17:14:29.993 回答
9

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));
}
于 2013-08-27T12:11:45.753 回答
8

这就是我使用的。只需继续从前面删除空间,然后,如果有任何剩余,从后面做同样的事情。

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
}
于 2013-11-12T22:56:44.480 回答
8

一种优雅的方式可以像

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));
}
于 2015-08-18T11:21:39.923 回答
7

对于它的价值,这是一个着眼于性能的修剪实现。它比我见过的许多其他修剪程序要快得多。它不使用迭代器和 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));
    }
}
于 2015-01-05T21:21:00.750 回答
7

这是使用正则表达式进行修剪的解决方案

#include <string>
#include <regex>

string trim(string str){
    return regex_replace(str, regex("(^[ ]+)|([ ]+$)"),"");
}
于 2019-11-08T19:59:33.370 回答
6

我想如果您开始要求修剪字符串的“最佳方法”,我会说一个好的实现将是:

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

显然有太多不同的方法可以解决这个问题,这绝对取决于您实际需要什么。但是,C 标准库在 <string.h> 中仍然有一些非常有用的函数,例如 memchr。C 仍然被认为是 IO 的最佳语言是有原因的——它的标准库是纯粹的效率。

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;
}
于 2013-11-16T20:10:05.067 回答
6

修剪 C++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());
}
于 2015-10-14T15:51:25.107 回答
5
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
于 2020-12-22T06:46:35.750 回答
4

为噪音贡献我的解决方案。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");  
}
于 2014-05-06T03:24:12.020 回答
4

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

while ( !s.empty() && isspace(s.back()) ) s.pop_back();
于 2016-01-31T18:54:26.550 回答
3

我不确定您的环境是否相同,但在我的环境中,空字符串大小写会导致程序中止。我要么用 if(!s.empty()) 包装那个擦除调用,要么使用前面提到的 Boost。

于 2008-10-19T20:03:35.197 回答
3

这是我想出的:

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

流提取会自动消除空格,所以这很有效。
如果我自己这么说的话,也很干净优雅。;)

于 2010-05-27T07:29:40.497 回答
3

这是我的版本:

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);
于 2016-08-31T14:41:21.593 回答
3

std::对于不习惯到处写,还不熟悉const-correctness、iterators、STL等的初学者来说,这是一个易于理解的解决方案algorithm……

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

希望能帮助到你...

于 2016-12-08T12:14:19.880 回答
2

上述方法很棒,但有时您希望将函数组合用于您的例程认为是空白的部分。在这种情况下,使用函子来组合操作可能会变得混乱,所以我更喜欢一个简单的循环,我可以为修剪进行修改。这是一个稍微修改过的修剪函数,它是从 SO 上的 C 版本复制而来的。在此示例中,我正在修剪非字母数字字符。

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);
}
于 2009-11-24T19:26:07.967 回答
2

那这个呢...?

#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++ 还是比较陌生,所以如果我在这里偏离基地,请原谅我。

于 2013-10-03T19:32:58.033 回答
2

这是一个直接的实现。对于这样一个简单的操作,您可能不应该使用任何特殊的构造。内置的 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);
}
于 2016-03-23T04:40:48.870 回答
1

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

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;
}
于 2010-08-24T17:57:50.290 回答
1

还有另一种选择 - 从两端删除一个或多个字符。

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);
}
于 2013-03-27T00:19:48.493 回答
1

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

它是最快的一个,即使添加更多字符进行检查(例如 \r\n 我看不到 \f\v 的用例)仍然比使用算法的解决方案更快。

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;
}
于 2016-03-15T00:11:17.990 回答
1

好的,这可能不是最快的,但它......很简单。

str = "   aaa    ";
int len = str.length();
// rtrim
while(str[len-1] == ' ') { str.erase(--len,1); }
// ltrim
while(str[0] == ' ') { str.erase(0,1); }
于 2019-09-07T04:27:18.273 回答
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 );
}
于 2013-11-28T09:57:33.880 回答
0

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

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 的情况类似,只是反转极化器,索引。

于 2014-04-02T15:54:50.353 回答
0

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

也适用于空字符串

于 2016-02-10T16:37:38.233 回答
0

接受的答案甚至Boost's 版本对我不起作用,所以我写了以下版本:

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

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

于 2020-02-15T22:35:31.100 回答
0

我正在使用这个:

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);
}
于 2015-10-11T02:39:40.657 回答
0

修剪两端。

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;
}
于 2020-08-19T22:11:28.813 回答
0

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

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);
}
于 2018-07-10T22:31:11.690 回答
0

穷人的字符串修剪(仅限空格):

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);
}
于 2021-01-15T03:53:17.240 回答
0

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

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

于 2020-07-15T17:06:51.203 回答
0

为什么不使用 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)); };
于 2020-08-05T17:46:04.377 回答
0

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

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;                                                                                                                                                                                                                               
}                                          
于 2018-09-26T19:31:33.327 回答
-1

看来我真的迟到了——我不敢相信这是 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);
}

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

于 2015-12-06T01:29:40.140 回答
-9

太烦人了,我

  • 必须谷歌它
  • 发现我必须使用火箭科学
  • 字符串中没有简单的 trim/toupper 函数

我来说,这是解决它的最快方法:

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

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

于 2018-07-04T15:47:32.307 回答