Artashes Karapetyan
Artashes Karapetyan

Reputation: 23

string erase using reversed remove_if

I've string s="12300" and now I am trying to erase the tail's 0s. So I am trying:

s.erase(s.rbegin(), std::remove_if(s.rbegin(), res.rend(),
                                  [](unsigned char x){
                                      static bool isPrevSymbol0 = true;
                                      if(!isPrevSymbol0)
                                      {
                                          return false;
                                      }
                                      isPrevSymbol0 = (x=='0');

                                      return isPrevSymbol0;
                                  }));

And I am getting this error:

no matching function for call to `std::basic_string::erase(std::basic_string::reverse_iterator, std::reverse_iterator<__gnu_cxx::__normal_iterator > >)`

How to solve the problem?

Upvotes: 2

Views: 460

Answers (4)

T.C.
T.C.

Reputation: 137315

basic_string's 150+ member functions are often ridiculed, but since they are there, let's put them to good use:

s.erase(s.find_last_not_of('0') + 1);

Upvotes: 2

Galik
Galik

Reputation: 48615

It seems the reverse iterators move the bad characters to the beginning of the string (rather than the end) and return the position after which we need to keep the characters.

So you need to erase from the beginning of the string to the value returned by remove_if.

std::string s = "12300";

s.erase(s.begin(), std::remove_if(s.rbegin(), s.rend(), [](char x){

    static bool isPrevSymbol0 = true;

    if(!isPrevSymbol0)
        return false;

    isPrevSymbol0 = (x=='0');

    return isPrevSymbol0;
}).base());

std::cout << s << '\n';

Also note we need to convert the returned reverse iterator to its corresponding normal iterator using base().

Upvotes: 0

DNKpp
DNKpp

Reputation: 277

A reverse_iterator is not a normal iterator. You have to use the base() function to use the erase() function of the std::string. An you have to reorder your arguments. You do it the wrong way round.

look here

std::string s="12300";
    s.erase(std::remove_if(s.rbegin(), s.rend(),
                                  [](unsigned char x){
                                      static bool isPrevSymbol0 = true;
                                      if(!isPrevSymbol0)
                                      {
                                          return false;
                                      }
                                      isPrevSymbol0 = (x=='0');

                                      return isPrevSymbol0;
                                  }).base(), s.end());
    std::cout << s;

EDIT: I think your code is not correct at all. std::remove_if doesn't break at the first returned false. I think it is the wrong algorithm for this task.

std::string s="0012300";
s.erase(std::find_if_not(s.rbegin(), s.rend(), [](char c){ return c == '0'; }).base(), s.end());
std::cout << s;

Upvotes: -2

Barry
Barry

Reputation: 303097

This is simply because std::string::erase takes a const_iterator, it doesn't take a reverse iterator. There's just no valid overload.

You need to explicitly convert the iterator from a reverse iterator to a forward iterator, via base(). And we can do this much more straightforwardly by finding the first non-0 character from the end, and erasing from there:

auto last_non_zero = std::find_if(s.rbegin(), s.rend(), [](char c){ return c != '0'; });
s.erase(last_non_zero.base(), s.end());
//                   ^^^^^^^

Upvotes: 3

Related Questions