Neil Kirk
Neil Kirk

Reputation: 21813

Remove first and last instance of a character from a string?

I assume the following doesn't compile because I am mixing forward and reverse iterators. Why can't I mix them like this? How can I get it to work? I want to remove the first and last quote of the string, but leave any internal quotes present.

temp.assign(find(value.begin(), value.end(), '\"'), find(value.rbegin(), value.rend(), '\"'));

I cannot even do this. What is the point of reverse iterators?

value.erase(find(value.begin(), value.end(), '\"'));
value.erase(find(value.rbegin(), value.rend(), '\"'));

Upvotes: 0

Views: 2107

Answers (5)

Marplesoft
Marplesoft

Reputation: 6240

How about this?

void stripLeadingAndTrailingQuotes(std::string& s) {
    if (s[0] == '\"')
        s.erase(0, 1);
    size_t last = s.length() - 1;
    if (s[last] == '\"')
        s.erase(last, 1);
}

Iterators are valid but I think the above is a lot more readable.

Upvotes: 0

Nathan Monteleone
Nathan Monteleone

Reputation: 5470

I think the problem is that erase expects a forward iterator, not a reverse iterator. As others have pointed out you can just use .base() on the result of find to convert them.

You could also use find_end instead.

Upvotes: 0

James Kanze
James Kanze

Reputation: 154047

The assign function (regardless of the type of temp) requires two iterators of the same type. A reverse iterator doesn't have the same type as a normal iterator. You can get at the underlying normal iterator using the base() function on the reverse iterator, but be careful; it is one behind the position the reverse iterator is pointing to. For example, if you write

temp.assign( find( value.begin(), value.end(), '\"' ),
             find( value.rbegin(), value.rend(), '\"').base() );

, the trailing '"' will be part of the resulting string.

This particular behavior is often what you want when you're using the results as a beginning iterator:

std::string( std::find( fn.rbegin(), fn.rend(), '.' ), fn.end() )

, for example, will give you all of the text after the last '.'. When using the results of a find with reverse iterators as the end criteron, you'll usually need to save it in a variable, and "correct" it in some way.

Finally, you should be extremely cautious about using the results of two finds to define a range, like you do above. If there's no '"' in your text, for example, you'll end up with the equivalent of:

temp.assign( value.end(), value.begin() );

, which isn't going to work.

EDIT:

As an example, if you don't want the '"' characters, I think the following should work:

//  Returns an empty string if there are not two " chars.
std::string
extractQuoted( std::string const& original )
{
    //  end points to one after the last '"', or begin() if no '"'.
    std::string::const_iterator end
        = std::find( original.rbegin(), original.rend(), '"' ).base();
    if ( end != original.begin() ) {
        -- end;    // Since we don't want the '"' in the final string
    }
    return std::string( std::find( original.begin(), end, '"' ), end );
}

(It's off the top of my head, so no guarantees, but it should get you started in the right direction.)

Upvotes: 3

user995502
user995502

Reputation:

You can also use

value.erase(0, value.find('\"') + 1);
value.erase(value.rfind('\"'), value.size());

Assuming the string will always contain atleast two "s

Upvotes: 0

bstamour
bstamour

Reputation: 7776

If you want to use reverse_itertators, call .base() on them to the underlying iterator type. e.g.

value.erase(find(value.begin(), value.end(), '\"'));
value.erase(find(value.rbegin(), value.rend(), '\"').base());

might do the trick.

Upvotes: 1

Related Questions