Cómo eliminar todas las apariciones de un char en una cadena de c ++


98

Estoy usando lo siguiente:

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

Pero esto está dando un error de compilación.


8
''no es un personaje de hecho.
n. 'pronombres' m.

3
Bueno, sin duda sería útil saber el error que está recibiendo.
SBI

3
Sea amable, hay muchos contextos donde reemplazar es un pensamiento apropiado, pero no este.
RichardPlunkett

Respuestas:


171

Básicamente, replacereemplaza un personaje por otro y ''no es un personaje. Lo que estás buscando es erase.

Vea esta pregunta que responde al mismo problema. En tu caso:

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

O use boostsi esa es una opción para usted, como:

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

Todo esto está bien documentado en sitios web de referencia . Pero si no conociera estas funciones, podría hacer fácilmente este tipo de cosas 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
¿No es el algoritmo que proporcionaste O(n^2)?
jww

@jww: Supongo que estás hablando de la última muestra de código y nes la longitud de la cadena original. Para cada carácter de entrada, hago una prueba de O(1)1 carácter y agrego 0 o 1 carácter. La adición de caracteres es si O(1)hay suficiente memoria reservada o O(current_length)si se asigna un nuevo búfer. Si lo hace output.reserve(str.size())antes del ciclo, esto nunca sucede y tiene un O(n)costo global . De lo contrario, de forma asintótica, supongo que el costo se O(n . log(n) )debe a la estrategia de reasignación de contenedores STL.
Antoine

5
Necesitaba #incluir <algoritmo>
S Meaden

Buena respuesta. Siempre es bueno si la respuesta contiene muchas soluciones. Para mí, la solución con el fores la más adecuada.
Dmitry Nichiporenko

@DmitryNichiporenko la respuesta con for no puede ser la más adecuada. Si tiene un predicado o una salida no vacía, preferiría considerar: output.reserve (str.size () + output.size ()); std :: copy_if (str.begin (), str.end (), std :: back_inserter (salida), [] (char c) {predicado de retorno (c);});
jimifiki

10

El algoritmo std::replacefunciona por elemento en una secuencia dada (por lo que reemplaza elementos con elementos diferentes y no puede reemplazarlo con nada ). Pero no hay un carácter vacío . Si desea eliminar elementos de una secuencia, los siguientes elementos deben moverse y std::replaceno funciona así.

Puede intentar usar std::remove( junto constd::erase ) para lograr esto.

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

Así es como lo hice.

O podrías hacer lo que Antoine mencionó:

Vea esta pregunta que responde al mismo problema. En tu caso:

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

1

Este código elimina la repetición de caracteres, es decir, si la entrada es aaabbcc, la salida 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

En caso de que tenga un predicatey / o un no vacío outputpara llenar con la cadena filtrada, consideraría:

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

En la pregunta original, el predicado es [](char c){return c != 'a';}


0

Según otras respuestas, aquí va un ejemplo más en el que eliminé todos los caracteres especiales en una cadena determinada:

#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 Salida:

Input:ra,..pha
Output:rapha

Input:ovo,
Output:ovo

Input:a.vo
Output:avo

Input:oi?
Output:oi

-1

Supongo que el método std: remove funciona pero estaba dando algún problema de compatibilidad con las inclusiones, así que terminé escribiendo esta pequeña función:

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

Solo usa como

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

y eliminará todas las ocurrencias de la lista de caracteres dada.

Esto también podría ser un poco más eficiente ya que el ciclo regresa después de la primera coincidencia, por lo que en realidad hacemos menos comparaciones.


1
Acertaste. En lugar de escribir el tuyo propio, es mejor que averigües por qué no puedes usar encabezados estándar de C ++.
xtofl

Bueno, esa es una opinión personal xtofl, no siempre es bueno usar el tercer código, en realidad no sabes lo que hace ni el rendimiento en lugar de escribir lo que necesitas específicamente.
Damien

1
Entiendo lo que dices. Sin embargo, es la humildad lo que me hace elegir la versión que ha sido revisada, probada y optimizada por escritores de bibliotecas profesionales a tiempo completo, en lugar de la mía. La biblioteca estándar puede considerarse un conocimiento necesario: sus funciones y su complejidad en tiempo de ejecución.
xtofl

Dejando a un lado las cadenas, es una solución de C a un problema de C ++. No creo que esto debería haber sido rechazado.
Búho

-1

Así es como lo hago:

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

Básicamente, cada vez que encuentro un carácter determinado, avanzo el desplazamiento y reubico el carácter en el índice correcto. No sé si esto es correcto o eficiente, estoy comenzando (una vez más) en C ++ y agradecería cualquier comentario al respecto.


4
Volviendo a esta pregunta 4 meses después, realmente no sé por qué no usé 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());

Eliminará Y y S mayúsculas de str, dejando "ourtring".

Tenga en cuenta que removees un algoritmo y necesita el encabezado <algorithm>incluido.


sí, creo que hay un bucle implícito sobre los caracteres de matriz que dejó fuera
RichardPlunkett
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.