So entfernen Sie alle Vorkommen eines Zeichens in einer C ++ - Zeichenfolge


98

Ich benutze folgendes:

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

Dies führt jedoch zu einem Kompilierungsfehler.


8
''ist in der Tat kein Charakter.
n. 'Pronomen' m.

3
Nun, es würde sicherlich helfen, den Fehler zu kennen, den Sie erhalten.
SBI

3
Sei nett, es gibt viele Kontexte, in denen das Ersetzen ein angemessener Gedanke ist, nur nicht dieser.
RichardPlunkett

Antworten:


171

Ersetzt grundsätzlich replaceeinen Charakter durch einen anderen und ''ist kein Charakter. Was Sie suchen, ist erase.

Siehe diese Frage, die das gleiche Problem beantwortet. In deinem Fall:

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

Oder verwenden Sie, boostwenn dies eine Option für Sie ist, wie:

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

Auf All dies ist gut dokumentierte Referenz Websites . Aber wenn Sie diese Funktionen nicht kennen, können Sie diese Dinge leicht von Hand erledigen:

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
Ist der von Ihnen bereitgestellte Algorithmus nicht O(n^2)?
JWW

@jww: Ich gehe davon aus, dass Sie über das letzte Codebeispiel sprechen und ndie ursprüngliche Zeichenfolgenlänge ist. Für jedes Eingabezeichen mache ich 1 Zeichentest O(1)und füge 0 oder 1 Zeichen hinzu. Das Anhängen von Zeichen O(1)ist ausreichend Speicherplatz reserviert oder O(current_length)wenn ein neuer Puffer zugewiesen wird. Wenn Sie dies output.reserve(str.size())vor der Schleife tun, geschieht dies nie und Sie haben globale O(n)Kosten. Ansonsten asymptotisch sind die Kosten O(n . log(n) )vermutlich auf die Strategie zur Neuzuweisung von STL-Containern zurückzuführen.
Antoine

5
Ich brauchte #include <algorithm>
S Meaden

Gute Antwort. Es ist immer gut, wenn die Antwort viele Lösungen enthält. Für mich ist die Lösung mit dem foram besten geeignet.
Dmitry Nichiporenko

@DmitryNichiporenko die Antwort mit dem für kann nicht die am besten geeignete sein. Wenn Sie ein Prädikat oder eine nicht leere Ausgabe haben, würde ich eher Folgendes in Betracht ziehen: output.reserve (str.size () + output.size ()); std :: copy_if (str.begin (), str.end (), std :: back_inserter (Ausgabe), [] (char c) {Rückgabeprädikat (c);});
Jimifiki

10

Der Algorithmus std::replacearbeitet pro Element in einer bestimmten Sequenz (ersetzt also Elemente durch andere Elemente und kann sie nicht durch nichts ersetzen ). Aber es gibt kein leeres Zeichen. Wenn Sie Elemente aus einer Sequenz entfernen möchten, müssen die folgenden Elemente verschoben werden und std::replacefunktionieren nicht so.

Sie können versuchen, std::remove( zusammen mitstd::erase ) dies zu erreichen.

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

8

Verwenden von 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;
}

So habe ich es gemacht.

Oder Sie könnten tun, was Antoine erwähnt hat:

Siehe diese Frage, die das gleiche Problem beantwortet. In deinem Fall:

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

1

Dieser Code entfernt die Wiederholung von Zeichen, dh wenn die Eingabe aaabbcc ist, ist die Ausgabe abc.

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;

1

Falls Sie eine predicateund / oder eine nicht leere haben output, die mit der gefilterten Zeichenfolge gefüllt werden soll, würde ich Folgendes in Betracht ziehen:

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

In der ursprünglichen Frage lautet das Prädikat [](char c){return c != 'a';}


0

Basierend auf anderen Antworten folgt ein weiteres Beispiel, in dem ich alle Sonderzeichen in einer bestimmten Zeichenfolge entfernt habe:

#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; 
}

Input vs Output:

Input:ra,..pha
Output:rapha

Input:ovo,
Output:ovo

Input:a.vo
Output:avo

Input:oi?
Output:oi

-1

Ich denke, die Methode std: remove funktioniert, aber es gab ein Kompatibilitätsproblem mit den Includes, so dass ich am Ende diese kleine Funktion schrieb:

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);
}

Verwenden Sie einfach als

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

und es wird das gesamte Auftreten der angegebenen Zeichenliste entfernt.

Dies könnte auch etwas effizienter sein, da die Schleife nach dem ersten Match zurückkehrt, sodass wir tatsächlich weniger Vergleiche durchführen.


1
Sie raten richtig. Finden Sie besser heraus, warum Sie keine Standard-C ++ - Header verwenden können, anstatt Ihre eigenen zu schreiben.
xtofl

Nun, das ist eine persönliche Meinung.
Damien

1
Ich verstehe was du meinst. Es ist jedoch Demut, die mich dazu bringt, mich für die Version zu entscheiden, die von professionellen Vollzeitbibliotheksautoren überprüft, getestet und optimiert wurde, und nicht für meine eigene. Die Standardbibliothek kann als erforderliches Wissen angesehen werden: ihre Funktionen sowie ihre Laufzeitkomplexität.
xtofl

Abgesehen von den Zeichenfolgen ist es eine C-Lösung für ein C ++ - Problem. Ich denke nicht, dass dies hätte abgelehnt werden sollen.
Eule

-1

So mache ich es:

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;
}

Grundsätzlich stelle ich den Offset immer dann vor, wenn ich ein bestimmtes Zeichen finde, und verschiebe das Zeichen in den richtigen Index. Ich weiß nicht, ob dies richtig oder effizient ist. Ich beginne (noch einmal) mit C ++ und würde mich über jede Eingabe dazu freuen.


4
Wenn ich 4 Monate später auf diese Frage zurückblicke, weiß ich wirklich nicht, warum ich nicht std :: erase oder std :: replace verwendet habe.
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());

Entfernt das Kapital Y und S aus str und hinterlässt "ourtring".

Beachten Sie, dass dies removeein Algorithmus ist und der Header <algorithm>enthalten sein muss.


Ja, ich denke, es gibt eine implizite Schleife über die Array-Zeichen, die er ausgelassen hat
RichardPlunkett
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.