Re: Truncate a C++ string

S

Stefan van Kessel

start with basic_string::rfind.

While rfind is perfectly fine I think find_last_of states in the intent
ever so slightly clearer.

std::string str = "/usr/local/src/test.dat";
std::string::size_type end = str.find_last_of('/');
if(end != str.npos)
str = str.substr(0, end+1);

If you need a null terminated string i.e. a C-string, you can use
str.c_str().
 
S

Stefan van Kessel

I like that method! Very clear to understand.
Actually str.erase(end+1) would be better than assigning the substr. I
didn't think of that before. But be sure to test if the character has
actually been found (here end!=str.npos) unless you already know for
sure it is in the string.
sbackup.replace(sbackup.rfind("/"), sbackup.length(), "");
which you wrote in the other message produces undefined behavior if
there is no "/" in the string because replace requires the first
argument to be smaller than the size of the string.
 
S

Stefan van Kessel

Um, not hardly. And it's bigger and slower. rfind does exactly what's
needed.

I'm not sure why you are convinced that it's "bigger and slower". If
there is more to it than the following, I would love to hear about it.
The standard requires the same behavior of both:
They both ought to behave as if they forward to their overload taking a
basic_string containing that one char.
(From 21.3.6:)
- Effects: Determines the highest position xpos, if possible, such that
both of the following conditions obtain:
rfind:
— xpos <= pos and xpos + str.size() <= size();
— at(xpos+I) == str.at(I) for all elements I of the string controlled by
str.
find_last_of:
— xpos <= pos and xpos < size();
— at(xpos) == str.at(I) for some element I of the string controlled by str.

With str.size() == 1 that amounts to the same.

In practice both the implementations that I checked: msvc10's and gcc
4.5's basic_string::find_last_of are a one line function, defined
inline, that does nothing but forward the call to rfind.

MSVC:
size_type find_last_of(_Elem _Ch, size_type _Off = npos) const
{ // look for _Ch before _Off
return (rfind((const _Elem *)&_Ch, _Off, 1));
}

While rfind('/') merely forwards to the same version of rfind, too:
size_type rfind(_Elem _Ch, size_type _Off = npos) const
{ // look for _Ch before _Off
return (rfind((const _Elem *)&_Ch, _Off, 1));
}

GCC:
* Note: equivalent to rfind(c, pos).
*/
size_type
find_last_of(_CharT __c, size_type __pos = npos) const
{ return this->rfind(__c, __pos); }


So find_last_of will not be faster than rfind but *usually* not slower
either. Anybody who doesn't agree that find_last_of might state the
intent clearer (and I don't feel strongly about that either; I admit
that it's hardly more than a bikeshed issue anyway :/) absolutely should
go with rfind but I'm not convinced that performance is a killer
argument here.

Have a nice day,
Stefan
 
J

James Kanze

On 2010-09-21 14:11:54 -0400, Stefan van Kessel said:
Um, not hardly. And it's bigger and slower. rfind does exactly
what's needed.

Until he has to port to Windows, and find either '/' or '\' :).

(I'll admit that I don't find anything using the std::string
member functions "clearer". I have to know the algorithms in
<algorithm> anyway, for the cases where I'm dealing with some
other sort of container. Why should a learn a separate and
distinct set just for std::string?)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top