ltrim and rtrim as standard methods in string class

Hi everybody
From time to time I see others, and myself, writing, again, a way to get rid of leading and trailing blanks in a string. When I moved to C++ from C and learned about the great string class, I thought it would bring this two methods (and even the frequent combination of both of them) with it. But it doesn't.

Does anyone knows if there's a good reason for this?. IMHO I think it would be perfectly justified. I know they can be easily implemented but, to me, it make sense to have them as a standard methods in this class.
These functions exist in boost (which you should already have installed if you're serious about using C++): http://www.boost.org/doc/libs/release/doc/html/string_algo/usage.html#idp166831648

C++ is maintained and improved by volunteer effort: the reason there are no trim functions for strings is simply that nobody found the time and desire to write a proposal that adds them to the standard library and to oversee its progress.

Actually, the string class is one of those that gets (or has gotten) a lot of attention. Many people consider it bloated as-is.

The string class is specifically as bare-bones as possible, in-line with other standard containers.

Things that manipulate a string (such as trimming, or case-insensitive comparison) are not as simple as people usually think, and don't actually belong in the string class, just as it would be unreasonable for a vector to know how to sort itself.

The string class (as with all standard containers) simply store data, and provide you methods to access it. Nothing more.

Hope this helps.
Thanks Cubbi and Duos for your answers.
Cubbi, actually, I see I'm less serious about using C++ than I thought becouse I've never heard about that library. But now I do.

Duoas, if what you say is the reason, then I don't understand why there is a set of methods, grouped under the name "modifiers", that perform a lot of operations that imply modifying strings (insert, append, replace, etc. See string reference in this page) which, in turn, end up handling memory, and that, I agree, is far from being easy.

I'm going to learn about boost library. I still think it would be great to have ltrim and rtrim as standard methods given what I said befor.

> I still think it would be great to have ltrim and rtrim as standard methods given what I said before.

Why do we need to bloat std::basic_string<> with special-purpose modifiers for removing leading or trailing white spaces?

We already have the general purpose std::regex_replace<>(), which can do so much more?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <string>
#include <regex>

int main()
{
    const std::string untrimmed = "    abcd    " ;
    std::cout << '|' << untrimmed << '|' << '\n' ; // |    abcd    |

    const std::string nothing = "" ;

    const auto ltrimmed = std::regex_replace( untrimmed, std::regex( "^\\s+" ), nothing ) ;
    std::cout << '|' << ltrimmed << '|' << '\n' ; // |abcd    |

    const auto rtrimmed = std::regex_replace( untrimmed, std::regex( "\\s+$" ), nothing ) ;
    std::cout << '|' << rtrimmed << '|' << '\n' ; // |    abcd|
}
There are many ways to do it, and OP has already indicated that he is familiar with at least one of them.

The string class itself can do it easily enough -- only it isn't obviously named with "trim":

1
2
3
TRIM LEFT IN-PLACE

s.erase( 0, s.find_first_not_of( delimiters ) );
1
2
3
TRIM LEFT COPY

s.substr( s.find_first_not_of( delimiters ) );


Duoas, if what you say is the reason, then I don't understand why there is a set of methods, grouped under the name "modifiers", that perform a lot of operations that imply modifying strings (insert, append, replace, etc. See string reference in this page) which, in turn, end up handling memory, and that, I agree, is far from being easy.

You are confusing things.

Insert, append, replace, etc are common container operations for any kind of data -- necessary to handle and maintain the data itself.

Things like trim, however, are common only to specialized subsets of data, and are not necessary to manage the data in memory.

I agree that it could be argued that trim is a common operation for string data, particularly as string data is typically textual data. But I'm not so sure the argument is potent enough to justify adding it to the list of things necessary just to manage the container.
Ok Duoas. I see the reason.

In my case, I face the situation of deciding where to place ltrim and rtrim functions to have them available for my projects (I do a lot of string processing coming from keyboard and files and always my first action is cleaning white spaces both leading and trailing). I've a library for them with some other functions but I end up mixing functions that not exactly fit with this ones. I always see them clearly attached to stirng class.

Next solution could be inheriting from string class, but it looks like it's not a good idea:

http://stackoverflow.com/questions/6006860/why-should-one-not-derive-from-c-std-string-class

Thanks for your opinions. They have been very usefull.
> I do a lot of string processing coming from keyboard and files
> and always my first action is cleaning white spaces both leading and trailing)

Just write a small helper function to do that.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <string>
#include <locale>

template< typename C, typename T, typename A >
std::basic_string<C,T,A> trim( const std::basic_string<C,T,A>& str,
                               const std::locale& loc = std::locale::classic() )
{
    auto begin = str.begin() ; // first non ws from left
    while( begin != str.end() && std::isspace( *begin, loc ) ) ++begin ;
    if( begin == str.end() ) return {} ; // EDIT

    auto rbegin = str.rbegin() ; // first non ws from right
    while( rbegin != str.rend() && std::isspace( *rbegin, loc ) ) ++rbegin ;

    return { begin, rbegin.base() } ;
}

int main()
{
    const std::string str = "   *abcd efgh ijkl*    " ;
    std::cout << '|' << str << "|\n" ;

    const std::string trimmed = trim(str) ;
    std::cout << '|' << trimmed << "|\n" ;


    const std::wstring wstr = L"   $12345$    " ;
    std::wcout << '|' << wstr << "|\n" ;

    const std::wstring wtrimmed = trim(wstr) ;
    std::wcout << '|' << wtrimmed << "|\n" ;
}

http://coliru.stacked-crooked.com/a/6088d39e5db3c18d
Last edited on
Just write a small helper function to do that


Yes, JLBorges, that's what I did, although without templates and using standard methods find_first_not_of () and find_last_not_of () instead of begin and end pointers .

My main concern was not about the functions themselves but about where to place them.

Thanks, anyway.
Last edited on
Put the functions in a header file, say str_utils.h

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef STR_UTILS_H_INCLUDED_
#define STR_UTILS_H_INCLUDED_

// place the functions here (either inline or static if they are not templated)
// eg.

inline std::string ltrim( const std::string& str )
{
    // ....
} 

#endif STR_UTILS_H_INCLUDED_ 


And then, #include "str_utils.h" and use the functions
Yes, that's what I did. Either str_utils.h, console_io.h (which is my case) or any other possibility is what I don't like. My preferred solution would have been just using them the same way I use length (), or erase ().
1
2
3
4
5
...
string str = "  dasdasdfa   ";
str = str.ltrim ();
str = str.rtrim ();
...


But I've learned that it's neither correct nor possible, so I have to get used to it. No problem ;)

Regards

We already have the general purpose std::regex_replace<>(), which can do so much more?



And I thought C++ programmers care about performance, cough cough...
You thought wrong. Compilers care about performance, we care about elegance.
> And I thought C++ programmers care about performance, cough cough...

C++ programmers care about performance where it matters; we can seamlessly operate at many different levels of abstraction.

Though it is unreasonable to expect a Java programmer, patently bereft of any real C++programming knowledge, to even begin to understand the concept.

You have made your obligatory political statement in a technical forum; now begone.
Topic archived. No new replies allowed.