Como remover todas as ocorrências de um caractere em uma string C ++


98

Estou usando o seguinte:

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

Mas isso está dando erro de compilação.


8
''não é um personagem de fato.
n. 'pronomes' m.

4
Bem, certamente ajudaria saber o erro que você está obtendo.
SBI

3
seja legal, há muitos contextos em que substituir é um pensamento apropriado, mas não este.
RichardPlunkett

Respostas:


171

Basicamente, replacesubstitui um personagem por outro e ''não é um personagem. O que você está procurando é erase.

Veja esta pergunta que responde ao mesmo problema. No seu caso:

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

Ou use boostse for uma opção para você, como:

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

Tudo isso está bem documentado em sites de referência . Mas se você não conhecesse essas funções, você poderia facilmente fazer este tipo de coisas manualmente:

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
Não é o algoritmo que você forneceu O(n^2)?
jww

@jww: Suponho que você esteja falando sobre o último exemplo de código e né o comprimento da string original. Para cada caractere de entrada, eu faço um teste de caractere O(1)e 0 ou 1 acréscimo de caractere. O acréscimo de caracteres O(1)se houver memória suficiente reservada ou O(current_length)se um novo buffer for alocado. Se você fizer isso output.reserve(str.size())antes do loop, isso nunca acontecerá e você terá um O(n)custo global . Caso contrário, de forma assintótica, acho que o custo se deve à O(n . log(n) )estratégia de realocação do contêiner STL.
Antoine,

5
Eu precisava de #include <algorithm>
S Meaden

Boa resposta. É sempre bom se a resposta contém muitas soluções. Para mim, a solução com o foré a mais adequada.
Dmitry Nichiporenko de

@DmitryNichiporenko a resposta com o para não pode ser a mais adequada. Se você tiver um predicado ou uma saída não vazia, prefiro considerar: output.reserve (str.size () + output.size ()); std :: copy_if (str.begin (), str.end (), std :: back_inserter (output), [] (char c) {return predicate (c);});
Jimifiki

10

O algoritmo std::replacefunciona por elemento em uma determinada sequência (portanto, substitui elementos por elementos diferentes e não pode substituí-lo por nada ). Mas não existe um personagem vazio . Se você quiser remover elementos de uma sequência, os seguintes elementos devem ser movidos e std::replacenão funcionam assim.

Você pode tentar usar std::remove( junto comstd::erase ) para conseguir isso.

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

8

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

É assim que eu fiz.

Ou você pode fazer o que Antoine mencionou:

Veja esta pergunta que responde ao mesmo problema. No seu caso:

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

1

Este código remove a repetição de caracteres, ou seja, se a entrada for aaabbcc, a saída será 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

Caso você tenha um predicatee / ou não vazio outputpara preencher com a string filtrada, eu consideraria:

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

Na pergunta original, o predicado é [](char c){return c != 'a';}


0

Com base em outras respostas, aqui vai mais um exemplo em que removi todos os caracteres especiais em uma determinada string:

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

Entrada vs saída:

Input:ra,..pha
Output:rapha

Input:ovo,
Output:ovo

Input:a.vo
Output:avo

Input:oi?
Output:oi

-1

Acho que o método std: remove funciona, mas estava apresentando alguns problemas de compatibilidade com os includes, então acabei escrevendo esta pequena função:

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 usar como

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

e removerá todas as ocorrências da lista de caracteres fornecida.

Isso também pode ser um pouco mais eficiente, pois o loop retorna após a primeira correspondência, portanto, fazemos menos comparação.


1
Você acha certo. Em vez de escrever o seu próprio, é melhor descobrir por que você não pode usar cabeçalhos C ++ padrão.
xtofl

Bem, essa é uma opinião pessoal xtofl, Nem sempre é bom usar o terceiro código - você na verdade não sabe o que ele faz nem as performances ao invés de escrever o que você precisa especificamente.
Damien

1
Eu entendo o que você quer dizer. No entanto, é humildade que me faz escolher a versão que foi revisada, testada e otimizada por escritores de biblioteca profissionais em tempo integral, ao invés da minha própria. A biblioteca padrão pode ser considerada como conhecimento necessário: suas funções, bem como sua complexidade de tempo de execução.
xtofl

Strings à parte, é uma solução C para um problema C ++. Eu não acho que isso deveria ter sido rejeitado.
Coruja

-1

É assim que eu faço:

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

Basicamente, sempre que encontro um determinado char, avanço o deslocamento e realoco o char para o índice correto. Não sei se isso é correto ou eficiente, estou começando (mais uma vez) em C ++ e gostaria de receber qualquer contribuição sobre isso.


4
Voltando a esta questão 4 meses depois, eu realmente não sei por que não usei std :: erase ou 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());

Irá remover Y e S maiúsculo de str, deixando "ourtring".

Observe que remove é um algoritmo e precisa do cabeçalho <algorithm>incluído.


sim, acho que há um loop implícito sobre os caracteres do array que ele deixou de fora
RichardPlunkett
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.