最好的修剪方法是什么?

时间:2022-09-15 20:31:17

I'm currently using the following code to right-trim all the std::strings in my programs:

我现在使用下面的代码来对所有std::字符串在我的程序中:

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

It works fine, but I wonder if there are some end-cases where it might fail?

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

Of course, answers with elegant alternatives and also left-trim solution are welcome.

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

36 个解决方案

#1


499  

EDIT Since c++17, some parts of the standard library were removed. Fortunately, starting with c++11, we have lambdas which are a superior solution.

编辑自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(), [](int 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(), [](int 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;
}

Thanks to https://*.com/a/44973498/524503 for bringing up the modern solution.

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

Original answer:

I tend to use one of these 3 for my trimming needs:

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

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

They are fairly self explanatory and work very well.

它们很容易解释,而且工作得很好。

EDIT: BTW, I have std::ptr_fun in there to help disambiguate std::isspace because there is actually a second definition which supports locales. This could have been a cast just the same, but I tend to like this better.

编辑:顺便说一下,我有std::ptr_fun在那里帮助消除了std::isspace,因为实际上有一个支持locale的第二个定义。这本来可以是一模一样的,但我更喜欢这样。

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

I am keeping the original answer above though for context and in the interest of keeping the high voted answer still available.

我将保留原来的答案,但在上下文和保持高投票答案的兴趣仍然可用。

#2


369  

Using Boost's string algorithms would be easiest:

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

#include <boost/algorithm/string.hpp>

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

str is now "hello world!". There's also trim_left and trim, which trims both sides.

str现在是“hello world!”还有trim_left和trim,两边都有修剪。


If you add _copy suffix to any of above function names e.g. trim_copy, the function will return a trimmed copy of the string instead of modifying it through a reference.

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

If you add _if suffix to any of above function names e.g. trim_copy_if, you can trim all characters satisfying your custom predicate, as opposed to just whitespaces.

如果您将_if后缀添加到上面的任何函数名中,例如trim_copy_if,那么您可以修改所有满足您的自定义谓词的字符,而不是仅仅使用空格。

#3


52  

Use the following code to right trim (trailing) spaces and tab characters from std::strings (ideone):

使用下面的代码对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));
}

And just to balance things out, I'll include the left trim code too (ideone):

为了平衡起见,我还将包括左修剪代码(ideone):

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

#4


48  

Bit late to the party, but never mind. Now C++11 is here, we have lambdas and auto variables. So my version, which also handles all-whitespace and empty strings, is:

聚会有点晚了,但没关系。现在,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));
}

We could make a reverse iterator from wsfront and use that as the termination condition in the second find_if_not but that's only useful in the case of an all-whitespace string, and gcc 4.8 at least isn't smart enough to infer the type of the reverse iterator (std::string::const_reverse_iterator) with auto. I don't know how expensive constructing a reverse iterator is, so YMMV here. With this alteration, the code looks like this:

我们可以从wsfront中创建一个反向迭代器,并将其用作第二个find_if_not中的终止条件,但这在纯空白字符串的情况下是有用的,而gcc 4.8至少不够聪明,无法推断出反向迭代器的类型(std:: 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());
}

#5


28  

What you are doing is fine and robust. I have used the same method for a long time and I have yet to find a faster method:

你所做的一切都很好,很有活力。我用同样的方法很长时间了,我还没有找到一个更快的方法:

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 (left & right)
inline std::string& trim(std::string& s, const char* t = ws)
{
    return ltrim(rtrim(s, t), t);
}

By supplying the characters to be trimmed you have the flexibility to trim non-whitespace characters and the efficiency to trim only the characters you want trimmed.

通过提供需要修剪的字符,您可以灵活地调整非空白字符和只修剪需要修剪的字符的效率。

#6


28  

Try this, it works for me.

试试这个,对我有用。

inline std::string trim(std::string& str)
{
    str.erase(0, str.find_first_not_of(' '));       //prefixing spaces
    str.erase(str.find_last_not_of(' ')+1);         //surfixing spaces
    return str;
}

#7


25  

I like tzaman's solution, the only problem with it is that it doesn't trim a string containing only spaces.

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

To correct that 1 flaw, add a str.clear() in between the 2 trimmer lines

若要纠正这一缺陷,请在2条微调线之间添加一个string .clear()。

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

#8


16  

In the case of an empty string, your code assumes that adding 1 to string::npos gives 0. string::npos is of type string::size_type, which is unsigned. Thus, you are relying on the overflow behaviour of addition.

在空字符串的情况下,您的代码假定将1添加到string::npos为0。字符串::npos类型为string::size_type,未签名。因此,您依赖于添加的溢出行为。

#9


16  

http://ideone.com/nFVtEo

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

#10


13  

Hacked off of Cplusplus.com

砍的Cplusplus.com

string choppa(const string &t, const string &ws)
{
    string str = t;
    size_t found;
    found = str.find_last_not_of(ws);
    if (found != string::npos)
        str.erase(found+1);
    else
        str.clear();            // str is all whitespace

    return str;
}

This works for the null case as well. :-)

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

#11


8  

My solution based on the answer by @Bill the Lizard.

我的解决方案是基于@Bill的答案。

Note that these functions will return the empty string if the input string contains nothing but whitespace.

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

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

#12


8  

My answer is an improvement upon the top answer for this post that trims control characters as well as spaces (0-32 and 127 on the ASCII table).

我的答案是对这篇文章的首要答案的改进,即trims控制字符以及空格(在ASCII表中0-32和127)。

std::isgraph determines if a character has a graphical representation, so you can use this to alter Evan's answer to remove any character that doesn't have a graphical representation from either side of a string. The result is a much more elegant solution:

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

Note: Alternatively you should be able to use std::iswgraph if you need support for wide characters, but you will also have to edit this code to enable std::wstring manipulation, which is something that I haven't tested (see the reference page for std::basic_string to explore this option).

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

#13


7  

This is what I use. Just keep removing space from the front, and then, if there's anything left, do the same from the back.

这是我用的。只需要把空间从前面移开,然后,如果有任何东西离开,就从后面做同样的事情。

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
}

#14


7  

For what it's worth, here is a trim implementation with an eye towards performance. It's much quicker than many other trim routines I've seen around. Instead of using iterators and std::finds, it uses raw c strings and indices. It optimizes the following special cases: size 0 string (do nothing), string with no whitespace to trim (do nothing), string with only trailing whitespace to trim (just resize the string), string that's entirely whitespace (just clear the string). And finally, in the worst case (string with leading whitespace), it does its best to perform an efficient copy construction, performing only 1 copy and then moving that copy in place of the original string.

对于它的价值,这里是一个微调实现,着眼于性能。这比我所见过的许多其他修剪方式要快得多。而不是使用迭代器和std::查找,它使用原始的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));
    }
}

#15


6  

With C++11 also came a regular expression module, which of course can be used to trim leading or trailing spaces.

使用c++ 11也有一个正则表达式模块,它当然可以用来修剪前导或尾随空格。

Maybe something like this:

也许是这样的:

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

#16


5  

An elegant way of doing it can be like

一种优雅的做法可以是这样。

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

And the supportive functions are implemented as:

支持功能的实现如下:

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

And once you've all these in place, you can write this as well:

一旦你把这些都写好了,你也可以这样写:

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

#17


4  

Here's what I came up with:

以下是我的想法:

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

Stream extraction eliminates whitespace automatically, so this works like a charm.
Pretty clean and elegant too, if I do say so myself. ;)

流提取可以自动消除空白,所以这就像一个符咒。如果我自己说的话,也很干净,也很优雅。,)

#18


4  

I guess if you start asking for the "best way" to trim a string, I'd say a good implementation would be one that:

我想,如果你开始要求“最好的方法”来修剪一个字符串,我认为一个好的实现应该是:

  1. Doesn't allocate temporary strings
  2. 不分配临时字符串
  3. Has overloads for in-place trim and copy trim
  4. 是否有内修和复位的过载?
  5. Can be easily customized to accept different validation sequences / logic
  6. 可以很容易地定制来接受不同的验证序列/逻辑吗?

Obviously there are too many different ways to approach this and it definitely depends on what you actually need. However, the C standard library still has some very useful functions in <string.h>, like memchr. There's a reason why C is still regarded as the best language for IO - its stdlib is pure efficiency.

显然,有太多不同的方法来解决这个问题,这完全取决于你实际需要什么。然而,C标准库在 中仍然有一些非常有用的函数。像memchr h >。有一个原因,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;
}

#19


4  

s.erase(0, s.find_first_not_of(" \n\r\t"));                                                                                               
s.erase(s.find_last_not_of(" \n\r\t")+1);   

#20


4  

Trim C++11 implementation:

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

#21


3  

I'm not sure if your environment is the same, but in mine, the empty string case will cause the program to abort. I would either wrap that erase call with an if(!s.empty()) or use Boost as already mentioned.

我不确定您的环境是否相同,但是在我的环境中,空字符串的情况会导致程序中止。我将使用if(! .empty())或使用Boost(如前面提到的那样)来结束该调用。

#22


3  

This can be done more simply in C++11 due to the addition of back() and pop_back().

由于添加了back()和pop_back(),所以在c++ 11中可以做得更简单。

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

#23


2  

Contributing my solution to the noise. trim defaults to creating a new string and returning the modified one while trim_in_place modifies the string passed to it. The trim function supports c++11 move semantics.

贡献我的解决方案。修剪默认值来创建一个新字符串,并在trim_in_place修改传递给它的字符串时返回修改过的字符串。修剪功能支持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");  
}

#24


2  

Here is my version:

这是我的版本:

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

#25


2  

Here's a solution easy to understand for beginners not used to write std:: everywhere and not yet familiar with const-correctness, iterators, STL algorithms, etc...

这里有一个很容易理解的解决方案,初学者不用写std::到处都不熟悉const-正确性、迭代器、STL算法等等……

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

Hope it helps...

希望它能帮助……

#26


1  

The above methods are great, but sometimes you want to use a combination of functions for what your routine considers to be whitespace. In this case, using functors to combine operations can get messy so I prefer a simple loop I can modify for the trim. Here is a slightly modified trim function copied from the C version here on SO. In this example, I am trimming non alphanumeric characters.

上面的方法很好,但是有时候您想要使用函数的组合来实现您的例程所认为的空白。在这种情况下,使用函数来合并操作可能会变得混乱,所以我喜欢一个简单的循环,我可以修改它的修剪。这是一个稍微修改过的修剪功能,从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);
}

#27


1  

This version trims internal whitespace and non-alphanumerics:

这个版本的内部空白和非字母数字:

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

#28


1  

Yet another option - removes one or more characters from both ends.

还有一个选项——从两端删除一个或多个字符。

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

#29


1  

What about this...?

关于这个…什么?

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

}

Note: I'm still relatively new to C++, so please forgive me if I'm off base here.

注意:我对c++还是比较陌生的,所以如果我在这里,请原谅我。

#30


1  

c++11:

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;

output:

输出:

hello

works fine also with empty strings

也适用于空字符串。

#1


499  

EDIT Since c++17, some parts of the standard library were removed. Fortunately, starting with c++11, we have lambdas which are a superior solution.

编辑自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(), [](int 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(), [](int 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;
}

Thanks to https://*.com/a/44973498/524503 for bringing up the modern solution.

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

Original answer:

I tend to use one of these 3 for my trimming needs:

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

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

They are fairly self explanatory and work very well.

它们很容易解释,而且工作得很好。

EDIT: BTW, I have std::ptr_fun in there to help disambiguate std::isspace because there is actually a second definition which supports locales. This could have been a cast just the same, but I tend to like this better.

编辑:顺便说一下,我有std::ptr_fun在那里帮助消除了std::isspace,因为实际上有一个支持locale的第二个定义。这本来可以是一模一样的,但我更喜欢这样。

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

I am keeping the original answer above though for context and in the interest of keeping the high voted answer still available.

我将保留原来的答案,但在上下文和保持高投票答案的兴趣仍然可用。

#2


369  

Using Boost's string algorithms would be easiest:

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

#include <boost/algorithm/string.hpp>

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

str is now "hello world!". There's also trim_left and trim, which trims both sides.

str现在是“hello world!”还有trim_left和trim,两边都有修剪。


If you add _copy suffix to any of above function names e.g. trim_copy, the function will return a trimmed copy of the string instead of modifying it through a reference.

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

If you add _if suffix to any of above function names e.g. trim_copy_if, you can trim all characters satisfying your custom predicate, as opposed to just whitespaces.

如果您将_if后缀添加到上面的任何函数名中,例如trim_copy_if,那么您可以修改所有满足您的自定义谓词的字符,而不是仅仅使用空格。

#3


52  

Use the following code to right trim (trailing) spaces and tab characters from std::strings (ideone):

使用下面的代码对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));
}

And just to balance things out, I'll include the left trim code too (ideone):

为了平衡起见,我还将包括左修剪代码(ideone):

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

#4


48  

Bit late to the party, but never mind. Now C++11 is here, we have lambdas and auto variables. So my version, which also handles all-whitespace and empty strings, is:

聚会有点晚了,但没关系。现在,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));
}

We could make a reverse iterator from wsfront and use that as the termination condition in the second find_if_not but that's only useful in the case of an all-whitespace string, and gcc 4.8 at least isn't smart enough to infer the type of the reverse iterator (std::string::const_reverse_iterator) with auto. I don't know how expensive constructing a reverse iterator is, so YMMV here. With this alteration, the code looks like this:

我们可以从wsfront中创建一个反向迭代器,并将其用作第二个find_if_not中的终止条件,但这在纯空白字符串的情况下是有用的,而gcc 4.8至少不够聪明,无法推断出反向迭代器的类型(std:: 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());
}

#5


28  

What you are doing is fine and robust. I have used the same method for a long time and I have yet to find a faster method:

你所做的一切都很好,很有活力。我用同样的方法很长时间了,我还没有找到一个更快的方法:

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 (left & right)
inline std::string& trim(std::string& s, const char* t = ws)
{
    return ltrim(rtrim(s, t), t);
}

By supplying the characters to be trimmed you have the flexibility to trim non-whitespace characters and the efficiency to trim only the characters you want trimmed.

通过提供需要修剪的字符,您可以灵活地调整非空白字符和只修剪需要修剪的字符的效率。

#6


28  

Try this, it works for me.

试试这个,对我有用。

inline std::string trim(std::string& str)
{
    str.erase(0, str.find_first_not_of(' '));       //prefixing spaces
    str.erase(str.find_last_not_of(' ')+1);         //surfixing spaces
    return str;
}

#7


25  

I like tzaman's solution, the only problem with it is that it doesn't trim a string containing only spaces.

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

To correct that 1 flaw, add a str.clear() in between the 2 trimmer lines

若要纠正这一缺陷,请在2条微调线之间添加一个string .clear()。

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

#8


16  

In the case of an empty string, your code assumes that adding 1 to string::npos gives 0. string::npos is of type string::size_type, which is unsigned. Thus, you are relying on the overflow behaviour of addition.

在空字符串的情况下,您的代码假定将1添加到string::npos为0。字符串::npos类型为string::size_type,未签名。因此,您依赖于添加的溢出行为。

#9


16  

http://ideone.com/nFVtEo

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

#10


13  

Hacked off of Cplusplus.com

砍的Cplusplus.com

string choppa(const string &t, const string &ws)
{
    string str = t;
    size_t found;
    found = str.find_last_not_of(ws);
    if (found != string::npos)
        str.erase(found+1);
    else
        str.clear();            // str is all whitespace

    return str;
}

This works for the null case as well. :-)

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

#11


8  

My solution based on the answer by @Bill the Lizard.

我的解决方案是基于@Bill的答案。

Note that these functions will return the empty string if the input string contains nothing but whitespace.

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

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

#12


8  

My answer is an improvement upon the top answer for this post that trims control characters as well as spaces (0-32 and 127 on the ASCII table).

我的答案是对这篇文章的首要答案的改进,即trims控制字符以及空格(在ASCII表中0-32和127)。

std::isgraph determines if a character has a graphical representation, so you can use this to alter Evan's answer to remove any character that doesn't have a graphical representation from either side of a string. The result is a much more elegant solution:

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

Note: Alternatively you should be able to use std::iswgraph if you need support for wide characters, but you will also have to edit this code to enable std::wstring manipulation, which is something that I haven't tested (see the reference page for std::basic_string to explore this option).

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

#13


7  

This is what I use. Just keep removing space from the front, and then, if there's anything left, do the same from the back.

这是我用的。只需要把空间从前面移开,然后,如果有任何东西离开,就从后面做同样的事情。

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
}

#14


7  

For what it's worth, here is a trim implementation with an eye towards performance. It's much quicker than many other trim routines I've seen around. Instead of using iterators and std::finds, it uses raw c strings and indices. It optimizes the following special cases: size 0 string (do nothing), string with no whitespace to trim (do nothing), string with only trailing whitespace to trim (just resize the string), string that's entirely whitespace (just clear the string). And finally, in the worst case (string with leading whitespace), it does its best to perform an efficient copy construction, performing only 1 copy and then moving that copy in place of the original string.

对于它的价值,这里是一个微调实现,着眼于性能。这比我所见过的许多其他修剪方式要快得多。而不是使用迭代器和std::查找,它使用原始的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));
    }
}

#15


6  

With C++11 also came a regular expression module, which of course can be used to trim leading or trailing spaces.

使用c++ 11也有一个正则表达式模块,它当然可以用来修剪前导或尾随空格。

Maybe something like this:

也许是这样的:

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

#16


5  

An elegant way of doing it can be like

一种优雅的做法可以是这样。

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

And the supportive functions are implemented as:

支持功能的实现如下:

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

And once you've all these in place, you can write this as well:

一旦你把这些都写好了,你也可以这样写:

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

#17


4  

Here's what I came up with:

以下是我的想法:

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

Stream extraction eliminates whitespace automatically, so this works like a charm.
Pretty clean and elegant too, if I do say so myself. ;)

流提取可以自动消除空白,所以这就像一个符咒。如果我自己说的话,也很干净,也很优雅。,)

#18


4  

I guess if you start asking for the "best way" to trim a string, I'd say a good implementation would be one that:

我想,如果你开始要求“最好的方法”来修剪一个字符串,我认为一个好的实现应该是:

  1. Doesn't allocate temporary strings
  2. 不分配临时字符串
  3. Has overloads for in-place trim and copy trim
  4. 是否有内修和复位的过载?
  5. Can be easily customized to accept different validation sequences / logic
  6. 可以很容易地定制来接受不同的验证序列/逻辑吗?

Obviously there are too many different ways to approach this and it definitely depends on what you actually need. However, the C standard library still has some very useful functions in <string.h>, like memchr. There's a reason why C is still regarded as the best language for IO - its stdlib is pure efficiency.

显然,有太多不同的方法来解决这个问题,这完全取决于你实际需要什么。然而,C标准库在 中仍然有一些非常有用的函数。像memchr h >。有一个原因,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;
}

#19


4  

s.erase(0, s.find_first_not_of(" \n\r\t"));                                                                                               
s.erase(s.find_last_not_of(" \n\r\t")+1);   

#20


4  

Trim C++11 implementation:

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

#21


3  

I'm not sure if your environment is the same, but in mine, the empty string case will cause the program to abort. I would either wrap that erase call with an if(!s.empty()) or use Boost as already mentioned.

我不确定您的环境是否相同,但是在我的环境中,空字符串的情况会导致程序中止。我将使用if(! .empty())或使用Boost(如前面提到的那样)来结束该调用。

#22


3  

This can be done more simply in C++11 due to the addition of back() and pop_back().

由于添加了back()和pop_back(),所以在c++ 11中可以做得更简单。

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

#23


2  

Contributing my solution to the noise. trim defaults to creating a new string and returning the modified one while trim_in_place modifies the string passed to it. The trim function supports c++11 move semantics.

贡献我的解决方案。修剪默认值来创建一个新字符串,并在trim_in_place修改传递给它的字符串时返回修改过的字符串。修剪功能支持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");  
}

#24


2  

Here is my version:

这是我的版本:

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

#25


2  

Here's a solution easy to understand for beginners not used to write std:: everywhere and not yet familiar with const-correctness, iterators, STL algorithms, etc...

这里有一个很容易理解的解决方案,初学者不用写std::到处都不熟悉const-正确性、迭代器、STL算法等等……

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

Hope it helps...

希望它能帮助……

#26


1  

The above methods are great, but sometimes you want to use a combination of functions for what your routine considers to be whitespace. In this case, using functors to combine operations can get messy so I prefer a simple loop I can modify for the trim. Here is a slightly modified trim function copied from the C version here on SO. In this example, I am trimming non alphanumeric characters.

上面的方法很好,但是有时候您想要使用函数的组合来实现您的例程所认为的空白。在这种情况下,使用函数来合并操作可能会变得混乱,所以我喜欢一个简单的循环,我可以修改它的修剪。这是一个稍微修改过的修剪功能,从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);
}

#27


1  

This version trims internal whitespace and non-alphanumerics:

这个版本的内部空白和非字母数字:

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

#28


1  

Yet another option - removes one or more characters from both ends.

还有一个选项——从两端删除一个或多个字符。

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

#29


1  

What about this...?

关于这个…什么?

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

}

Note: I'm still relatively new to C++, so please forgive me if I'm off base here.

注意:我对c++还是比较陌生的,所以如果我在这里,请原谅我。

#30


1  

c++11:

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;

output:

输出:

hello

works fine also with empty strings

也适用于空字符串。