Come rimuovere tutte le occorrenze di un carattere in una stringa c ++


98

Sto usando quanto segue:

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

Ma questo sta dando un errore di compilazione.


8
''non è davvero un personaggio.
n. 'pronomi' m.

4
Bene, sarebbe sicuramente utile conoscere l'errore che stai ricevendo.
SBI

3
sii gentile, ci sono molti contesti in cui sostituire è un pensiero appropriato, ma non questo.
RichardPlunkett

Risposte:


171

Fondamentalmente, replacesostituisce un personaggio con un altro e ''non è un personaggio. Quello che stai cercando èerase .

Vedi questa domanda che risponde allo stesso problema. Nel tuo caso:

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

Oppure usa boostse questa è un'opzione per te, come:

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

Tutto questo è ben documentato sui siti web di riferimento . Ma se non conoscessi queste funzioni, potresti facilmente fare questo tipo di cose a mano:

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
Non è l'algoritmo che hai fornito O(n^2)?
jww

@ jww: presumo tu stia parlando dell'ultimo esempio di codice e che nsia la lunghezza della stringa originale. Per ogni carattere di input, eseguo un test di carattere O(1)e aggiungo 0 o 1 carattere. Il carattere da aggiungere è O(1)se la memoria è sufficiente o O(current_length)se viene allocato un nuovo buffer. Se lo fai output.reserve(str.size())prima del ciclo questo non accade mai e hai un O(n)costo globale . In caso contrario, in modo asintotico, immagino che il costo sia O(n . log(n) )dovuto alla strategia di riallocazione del contenitore STL.
Antoine

5
Avevo bisogno di #include <algoritmo>
S Meaden

Bella risposta. Va sempre bene se la risposta contiene molte soluzioni. Per me la soluzione con la forè la più adatta.
Dmitry Nichiporenko

@DmitryNichiporenko la risposta con il per non può essere la più adatta. Se hai un predicato o un output non vuoto, preferirei considerare: output.reserve (str.size () + output.size ()); std :: copy_if (str.begin (), str.end (), std :: back_inserter (output), [] (char c) {return predicate (c);});
jimifiki

10

L'algoritmo std::replacefunziona per elemento su una data sequenza (quindi sostituisce elementi con elementi diversi e non può sostituirlo con niente ). Ma non esiste un carattere vuoto . Se vuoi rimuovere elementi da una sequenza, i seguenti elementi devono essere spostati e std::replacenon funziona in questo modo.

Puoi provare a usare std::remove( insieme astd::erase ) per ottenere questo risultato.

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

8

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

Ecco come l'ho fatto.

Oppure potresti fare come ha detto Antoine:

Vedi questa domanda che risponde allo stesso problema. Nel tuo caso:

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

1

Questo codice rimuove la ripetizione di caratteri, cioè, se l'input è aaabbcc, l'output sarà 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

Nel caso tu abbia un predicatee / o un non vuoto outputda riempire con la stringa filtrata, prenderei in considerazione:

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

Nella domanda originale il predicato è [](char c){return c != 'a';}


0

Sulla base di altre risposte, ecco un altro esempio in cui ho rimosso tutti i caratteri speciali in una determinata stringa:

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

Ingresso vs uscita:

Input:ra,..pha
Output:rapha

Input:ovo,
Output:ovo

Input:a.vo
Output:avo

Input:oi?
Output:oi

-1

Immagino che il metodo std: remove funzioni ma dava qualche problema di compatibilità con gli include, quindi ho finito per scrivere questa piccola funzione:

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

Basta usare come

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

e rimuoverà tutte le occorrenze della lista di caratteri data.

Questo potrebbe anche essere un po 'più efficiente poiché il ciclo ritorna dopo la prima corrispondenza, quindi in realtà facciamo meno confronti.


1
Hai indovinato. Piuttosto che scrivere il tuo, è meglio scoprire perché non puoi usare le intestazioni C ++ standard.
xtofl

Beh, questa è un'opinione personale xtofl, non è sempre bene usare il 3 ° codice in realtà non sai cosa fa né le prestazioni piuttosto che scrivere ciò di cui hai specificamente bisogno.
Damien

1
Capisco cosa intendi. È l'umiltà che mi fa scegliere la versione che è stata rivista, testata, ottimizzata da scrittori di biblioteche professionisti a tempo pieno, piuttosto che dalla mia. La libreria standard può essere considerata come una conoscenza richiesta: le sue funzioni e la sua complessità di runtime.
xtofl

Stringhe a parte, è una soluzione C a un problema C ++. Non credo che questo avrebbe dovuto essere bocciato.
Gufo

-1

Ecco come lo faccio:

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

Fondamentalmente ogni volta che trovo un dato carattere, avanzo l'offset e riposiziono il carattere nell'indice corretto. Non so se sia corretto o efficiente, sto iniziando (ancora una volta) in C ++ e apprezzerei qualsiasi input in merito.


4
Ripensando a questa domanda 4 mesi dopo, non so davvero perché non ho usato std :: erase o 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());

Rimuoverà la Y e la S maiuscole da str, lasciando "ourtring".

Nota che removeè un algoritmo e richiede che sia <algorithm>inclusa l'intestazione .


sì, penso che ci sia un loop implicito sui caratteri dell'array hte che ha lasciato fuori
RichardPlunkett
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.