Jak usunąć wszystkie wystąpienia znaku w ciągu C ++


104

Używam następujących:

replace (str1.begin(), str1.end(), 'a' , '')

Ale to daje błąd kompilacji.


9
''nie jest w istocie postacią.
n. zaimki m.

5
Cóż, z pewnością pomogłoby poznanie błędu, który otrzymujesz.
SBI

3
bądź miły, istnieje wiele kontekstów, w których zastąpienie jest właściwą myślą, ale nie tym.
RichardPlunkett

Odpowiedzi:


176

Zasadniczo replacezastępuje postać inną i ''nie jest postacią. To, czego szukasz, to erase.

Zobacz to pytanie, które odpowiada na ten sam problem. W Twoim przypadku:

#include <algorithm>
str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());

Lub użyj, boostjeśli to opcja dla Ciebie, na przykład:

#include <boost/algorithm/string.hpp>
boost::erase_all(str, "a");

Wszystko to jest dobrze udokumentowane na referencyjnych stron internetowych . Ale jeśli nie znasz tych funkcji, możesz łatwo zrobić tego rodzaju rzeczy ręcznie:

std::string output;
output.reserve(str.size()); // optional, avoids buffer reallocations in the loop
for(size_t i = 0; i < str.size(); ++i)
  if(str[i] != 'a') output += str[i];

2
Czy to nie algorytm, który podałeś O(n^2)?
jww

1
@jww: Zakładam, że mówisz o ostatnim przykładzie kodu i njest to oryginalna długość ciągu. Dla każdego znaku wejściowego wykonuję 1 test znaku O(1)i dołączam 0 lub 1 znak. Dołączanie znaków O(1)jest wystarczające, O(current_length)jeśli zarezerwowano wystarczającą ilość pamięci lub przydzielono nowy bufor. Jeśli zrobisz to output.reserve(str.size())przed pętlą, nigdy się to nie zdarzy i masz globalny O(n)koszt. W przeciwnym razie asymptotycznie, myślę, że koszt wynika O(n . log(n) )ze strategii realokacji kontenerów STL.
Antoine

5
Potrzebowałem #include <algorithm>
S Meaden

Niezła odpowiedź. Zawsze dobrze, jeśli odpowiedź zawiera wiele rozwiązań. Dla mnie fornajbardziej odpowiednie jest rozwiązanie z symbolem.
Dmitry Nichiporenko

@DmitryNichiporenko odpowiedź z for nie może być najbardziej odpowiednia. Jeśli masz predykat lub niepuste wyjście, wolałbym rozważyć: output.reserve (str.size () + output.size ()); std :: copy_if (str.begin (), str.end (), std :: back_inserter (wyjście), [] (char c) {return predicate (c);});
jimifiki

11

Algorytm std::replacedziała na element w danej sekwencji (więc zastępuje elementy innymi elementami i nie może go niczym zastąpić ). Ale nie ma pustego charakteru. Jeśli chcesz usunąć elementy z sekwencji, poniższe elementy muszą zostać przeniesione i std::replacenie działa w ten sposób.

Możesz spróbować użyć std::remove( razem zstd::erase ), aby to osiągnąć.

str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());

9

Używając copy_if:

#include <string>
#include <iostream>
#include <algorithm>
int main() {
    std::string s1 = "a1a2b3c4a5";
    char s2[256];
    std::copy_if(s1.begin(), s1.end(), s2, [](char c){return c!='a';});
    std::cout << s2 << std::endl;
    return 0;
}

3
string RemoveChar(string str, char c) 
{
   string result;
   for (size_t i = 0; i < str.size(); i++) 
   {
          char currentChar = str[i];
          if (currentChar != c)
              result += currentChar;
   }
       return result;
}

Tak to zrobiłem.

Lub możesz zrobić tak, jak wspomniał Antoine:

Zobacz to pytanie, które odpowiada na ten sam problem. W Twoim przypadku:

#include <algorithm>
str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());

1

W przypadku, gdy masz a predicatei / lub niepusty outputdo wypełnienia przefiltrowanym ciągiem, rozważę:

output.reserve(str.size() + output.size());  
std::copy_if(str.cbegin(), 
             str.cend(), 
             std::back_inserter(output), 
             predicate});

W pierwotnym pytaniu orzeczeniem jest [](char c){return c != 'a';}


1

Ten kod usuwa powtórzenia znaków, tj. Jeśli wejście to aaabbcc, to wyjście będzie miało postać abc. (tablica musi być posortowana, aby ten kod działał)

cin >> s;
ans = "";
ans += s[0];
for(int i = 1;i < s.length();++i)
if(s[i] != s[i-1])
    ans += s[i];
cout << ans << endl;

0

Opierając się na innych odpowiedziach, oto jeszcze jeden przykład, w którym usunąłem wszystkie specjalne znaki z danego ciągu:

#include <iostream>
#include <string>
#include <algorithm>

std::string chars(".,?!.:;_,!'\"-");

int main(int argc, char const *argv){

  std::string input("oi?");
  std::string output = eraseSpecialChars(input);   

 return 0;
}




std::string eraseSpecialChars(std::string str){

std::string newStr;
    newStr.assign(str);  

    for(int i = 0; i < str.length(); i++){
        for(int  j = 0; j < chars.length(); j++ ){
            if(str.at(i) == chars.at(j)){
                char c = str.at(i);
                newStr.erase(std::remove(newStr.begin(), newStr.end(), c), newStr.end());
            }
        }

    }      

return newStr; 
}

Wejście vs wyjście:

Input:ra,..pha
Output:rapha

Input:ovo,
Output:ovo

Input:a.vo
Output:avo

Input:oi?
Output:oi

0

70% szybsze rozwiązanie niż najlepsza odpowiedź

        void removeCharsFromString(std::string& str, const char* charsToRemove)
        {
            size_t charsToRemoveLen = strlen(charsToRemove);
            std::remove_if(str.begin(), str.end(), [charsToRemove, charsToRemoveLen](char ch) -> bool
                {
                    for (int i = 0; i < charsToRemoveLen; ++i) {
                        if (ch == charsToRemove[i])
                            return true;
                    }
                    return false;
                });
        }

-1

Wydaje mi się, że metoda std: remove działa, ale dawała pewien problem ze zgodnością z dołączeniami, więc napisałem tę małą funkcję:

string removeCharsFromString(const string str, char* charsToRemove )
{
    char c[str.length()+1]; // + terminating char
    const char *p = str.c_str();
    unsigned int z=0, size = str.length();
    unsigned int x;
    bool rem=false;

    for(x=0; x<size; x++)
    {
        rem = false;
        for (unsigned int i = 0; charsToRemove[i] != 0; i++)
        {
            if (charsToRemove[i] == p[x])
            {
                rem = true;
                break;
            }
        }
        if (rem == false) c[z++] = p[x];
    }

    c[z] = '\0';
    return string(c);
}

Po prostu użyj jako

myString = removeCharsFromString (myString, "abc \ r");

i usunie wszystkie wystąpienia z podanej listy znaków.

Może to być również nieco bardziej wydajne, gdy pętla powraca po pierwszym dopasowaniu, więc w rzeczywistości robimy mniej porównań.


1
Zgadujesz dobrze. Zamiast pisać własne, lepiej dowiedz się, dlaczego nie możesz używać standardowych nagłówków C ++.
xtofl

Cóż, to osobista opinia xtofl, nie zawsze dobrze jest używać trzeciego kodu, w rzeczywistości nie wiesz, co on robi, ani wydajności, zamiast pisać to, czego konkretnie potrzebujesz.
Damien

1
Rozumiem co masz na myśli. Jednak to pokora sprawia, że ​​wybieram wersję, która została sprawdzona, przetestowana, zoptymalizowana przez profesjonalnych pisarzy bibliotekarskich w pełnym wymiarze godzin, a nie moja własna. Standardowe biblioteki mogą być traktowane jako wymaganej wiedzy: jego funkcje oraz jego złożoności wykonawczego.
xtofl

Pomijając ciągi znaków, jest to rozwiązanie C ++ do problemu. Nie sądzę, że powinno to zostać odrzucone.
Sowa,

-1

Oto jak to robię:

std::string removeAll(std::string str, char c) {
    size_t offset = 0;
    size_t size = str.size();

    size_t i = 0;
    while (i < size - offset) {
        if (str[i + offset] == c) {
            offset++;
        }

        if (offset != 0) {
            str[i] = str[i + offset];
        }

        i++;
    }

    str.resize(size - offset);
    return str;
}

Zasadniczo za każdym razem, gdy znajduję dany znak, przesuwam przesunięcie i przenoszę znak do właściwego indeksu. Nie wiem, czy to jest poprawne czy wydajne, zaczynam (jeszcze raz) od C ++ i byłbym wdzięczny za wszelkie uwagi na ten temat.


4
Patrząc wstecz na to pytanie 4 miesiące później, naprawdę nie wiem, dlaczego nie użyłem std :: erase lub std :: replace.
Ricardo Pieper

-3
#include <string>
#include <algorithm>
std::string str = "YourString";
char chars[] = {'Y', 'S'};
str.erase (std::remove(str.begin(), str.end(), chars[i]), str.end());

Usunie wielkie Y i S ze str, pozostawiając „ourtring”.

Zauważ, że removejest to algorytm i wymaga <algorithm>dołączonego nagłówka .


tak, myślę, że istnieje domniemana pętla nad znakami tablicy hte, którą
pominął
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.