Eliminar espacios de std :: string en C ++


222

¿Cuál es la forma preferida de eliminar espacios de una cadena en C ++? Podría recorrer todos los personajes y construir una nueva cadena, pero ¿hay una mejor manera?

Respuestas:


257

Lo mejor que puede hacer es usar el algoritmo remove_ify el espacio de emisión:

remove_if(str.begin(), str.end(), isspace);

Ahora el algoritmo en sí mismo no puede cambiar el contenedor (solo modificar los valores), por lo que realmente baraja los valores y devuelve un puntero a donde debería estar el final ahora. Entonces tenemos que llamar a string :: erase para modificar realmente la longitud del contenedor:

str.erase(remove_if(str.begin(), str.end(), isspace), str.end());

También debemos tener en cuenta que remove_if hará como máximo una copia de los datos. Aquí hay una implementación de muestra:

template<typename T, typename P>
T remove_if(T beg, T end, P pred)
{
    T dest = beg;
    for (T itr = beg;itr != end; ++itr)
        if (!pred(*itr))
            *(dest++) = *itr;
    return dest;
}

54
Debido a que 'isspace' tiene sobrecargas, es probable que deba calificar el código genérico para usar :: isspace (la implementación de C que no tiene una configuración regional) o ser recibido con errores crípticos de creación de instancias.
Bklyn

44
Todos: tenga cuidado con el método anterior (las dos líneas simples, no la versión con plantilla, aunque puede tener el mismo problema). Lo usé en un proyecto sin darme cuenta de que no siempre es correcto. Por ejemplo, si le pasa la cadena "1 + 1", devuelve "1 + 11". Cambié al método de @rupello a continuación y funcionó bien para este caso. ¡Feliz codificación!
JoeB

66
@ Joe La respuesta menciona explícitamente que debe llamar erasedespués. Eso devolverá el resultado correcto.
Konrad Rudolph

31
-1 este uso de isspacees UB para todos los juegos de caracteres excepto el ASCII original de 7 bits. C99 §7.4 / 1. que no sorprende mí que ha sido upvoted por una suma de 71 votos por ahora, a pesar de ser muy mal consejo.
Saludos y hth. - Alf

16
Solo para repetir, el código en esta respuesta pasa valores negativos (diferentes de EOF) a isspace, para todos los caracteres no ASCII, con la opción predeterminada de firma en la práctica char. Por lo tanto, tiene un comportamiento indefinido . Lo estoy repitiendo porque sospecho un intento deliberado de ahogar ese hecho en ruido.
Saludos y hth. - Alf

100
std::string::iterator end_pos = std::remove(str.begin(), str.end(), ' ');
str.erase(end_pos, str.end());

31
Mi voto positivo por el lenguaje canónico de borrar / eliminar. Se puede convertir en una sola línea: str.erase (std :: remove (str.begin (), str.end (), ''), str.end ());
Bklyn

11
Nota: debe incluir <algorithm>para que esto funcione.
Tara

37

De gamedev

string.erase(std::remove_if(string.begin(), string.end(), std::isspace), string.end());

22
Esto no se compilará en implementaciones que cumplan con los estándares debido a las sobrecargas de toma de locación de std :: isspace. Deberá usar :: isspace o realizar algunas maquinaciones ilegibles con std :: bind2nd. ¿No es hermoso el código genérico?
Bklyn

También tenga en cuenta que si alguno de los caracteres es negativo (por ejemplo, un carácter UTF8 cuando se firma el carácter), el uso de ::isspacees UB.
Martin Bonner apoya a Monica el

30

¿Puedes usar Boost String Algo? http://www.boost.org/doc/libs/1_35_0/doc/html/string_algo/usage.html#id1290573

erase_all(str, " "); 

3
Es más lento que el remove_if(str.begin(), str.end(), isspace);que mencionó Matt Price. No se porque. En realidad, todas las cosas de impulso, que tienen alternativas STL, son más lentas que las correspondientes a gcc (todas las que probé). ¡Algunos de ellos son inmensamente más lentos! (hasta 5 veces en inserciones de mapas desordenados) Tal vez se deba a la memoria caché de la CPU del entorno compartido o algo similar.
Etherealone

16

Para recortar, use algoritmos de cadena de refuerzo :

#include <boost/algorithm/string.hpp>

using namespace std;
using namespace boost;

// ...

string str1(" hello world! ");
trim(str1);      // str1 == "hello world!"


12

Hola, puedes hacer algo así. Esta función elimina todos los espacios.

string delSpaces(string &str) 
{
   str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
   return str;
}

Hice otra función, que elimina todos los espacios innecesarios.

string delUnnecessary(string &str)
{
    int size = str.length();
    for(int j = 0; j<=size; j++)
    {
        for(int i = 0; i <=j; i++)
        {
            if(str[i] == ' ' && str[i+1] == ' ')
            {
                str.erase(str.begin() + i);
            }
            else if(str[0]== ' ')
            {
                str.erase(str.begin());
            }
            else if(str[i] == '\0' && str[i-1]== ' ')
            {
                str.erase(str.end() - 1);
            }
        }
    }
    return str;
}

8
string replaceinString(std::string str, std::string tofind, std::string toreplace)
{
        size_t position = 0;
        for ( position = str.find(tofind); position != std::string::npos; position = str.find(tofind,position) )
        {
                str.replace(position ,1, toreplace);
        }
        return(str);
}

úsalo:

string replace = replaceinString(thisstring, " ", "%20");
string replace2 = replaceinString(thisstring, " ", "-");
string replace3 = replaceinString(thisstring, " ", "+");

7

Si desea hacer esto con una macro fácil, aquí hay una:

#define REMOVE_SPACES(x) x.erase(std::remove(x.begin(), x.end(), ' '), x.end())

Esto supone que lo has hecho, #include <string>por supuesto.

Llámalo así:

std::string sName = " Example Name ";
REMOVE_SPACES(sName);
printf("%s",sName.c_str()); // requires #include <stdio.h>

55
¿Por qué usarías una macro para esto?
dani

1
Menos tipeo de teclado para una tarea común.
Volomike

3
Igualmente corto para el sitio de llamada es llamar a una función que toma una referencia de valor a una cadena. Las macros pueden tener comportamientos sorprendentes al interactuar con sus argumentos (especialmente con efectos secundarios), pero lo que es peor, si están involucrados en un error, sus nombres no aparecen en los mensajes del compilador, su implementación sí.
Chris Uzdavinis

2

Usé el siguiente trabajo durante mucho tiempo, no estoy seguro de su complejidad.

s.erase(std::unique(s.begin(),s.end(),[](char s,char f){return (f==' '||s==' ');}),s.end());

cuando quieres eliminar el personaje ' 'y algunos, por ejemplo, - usan

s.erase(std::unique(s.begin(),s.end(),[](char s,char f){return ((f==' '||s==' ')||(f=='-'||s=='-'));}),s.end());

Del mismo modo, solo aumente el ||número de caracteres que desea eliminar no es 1

pero como lo mencionaron otros, el idioma de borrar borrado también parece estar bien.


1
string removeSpaces(string word) {
    string newWord;
    for (int i = 0; i < word.length(); i++) {
        if (word[i] != ' ') {
            newWord += word[i];
        }
    }

    return newWord;
}

Este código básicamente toma una cadena e itera a través de cada carácter que contiene. Luego verifica si esa cadena es un espacio en blanco, si no lo es, el carácter se agrega a una nueva cadena.


1
   #include <algorithm>
   using namespace std;

   int main() {
       .
       .
       s.erase( remove( s.begin(), s.end(), ' ' ), s.end() );
       .
       .
   }

Fuente:

Referencia tomada de este foro.


1
Esto realmente no agrega nada más de lo que esta respuesta ya hace. ¿Hay más explicaciones o detalles que pueda agregar para que su respuesta sea de mayor calidad y valga la pena seguir con esta pregunta?
Das_Geek

Creo que es más simple , porque hace lo mismo en una declaración.
John

2
¡Excelente! Luego ponga ese razonamiento como una explicación directamente en su respuesta . La pregunta original tiene más de once años , y sin una justificación, su respuesta podría verse como ruido en comparación con las otras respuestas aceptadas y bien votadas. Tener esa explicación ayudará a evitar que su respuesta sea eliminada.
Das_Geek

Eso sería bueno, pero no pude entender eso, ¿cómo debería poner eso en mi respuesta ... que mi respuesta es mejor que esta respuesta . ? Sería un gran placer poder editar mi respuesta.
John

2
Desafortunadamente, editar su respuesta para agregar ese contenido iría en contra de las pautas de edición , y mi edición probablemente se rechazaría o se revertiría más tarde. Puede usar el primer enlace en este comentario para editar la respuesta usted mismo. Es totalmente aceptable afirmar que cree que su respuesta es mejor que otra, y justificarla. La comunidad decidirá si tienes razón votando a favor o en contra.
Das_Geek

0

En C ++ 20 puede usar la función gratuita std :: erase

std::string str = " Hello World  !";
std::erase(str, ' ');

Ejemplo completo:

#include<string>
#include<iostream>

int main() {
    std::string str = " Hello World  !";
    std::erase(str, ' ');
    std::cout << "|" << str <<"|";
}

Yo imprimo | para que sea obvio que también se elimina el espacio al principio.

nota: esto elimina solo el espacio, no todos los demás caracteres posibles que pueden considerarse espacios en blanco, consulte https://en.cppreference.com/w/cpp/string/byte/isspace


0

Elimina todos los caracteres de espacio en blanco , como tabulaciones y saltos de línea (C ++ 11):

string str = " \n AB cd \t efg\v\n";
str = regex_replace(str,regex("\\s"),"");

¿Por qué recomendaría este enfoque sobre la respuesta aceptada de @ Matt-Price de hace más de una década?
Jeremy Caney

Deje que todas las soluciones se presenten aquí. Quizás alguien necesite esta solución.
AnselmRu

No estoy discutiendo en contra de eso. Estoy diciendo que facilite a las personas evaluar diferentes enfoques al explicar las diferencias y para qué escenarios podrían ser más adecuados.
Jeremy Caney

1
Probablemente esta solución no sea la más económica, pero le permite deshacerse de todos los caracteres de espacio en blanco '\ s', no solo espacios ''.
AnselmRu

0
  string str = "2C F4 32 3C B9 DE";
  str.erase(remove(str.begin(),str.end(),' '),str.end());
  cout << str << endl;

salida: 2CF4323CB9DE


-1
string removespace(string str)
{    
    int m = str.length();
    int i=0;
    while(i<m)
    {
        while(str[i] == 32)
        str.erase(i,1);
        i++;
    }    
}

3
Generalmente se prefiere que agregue una breve explicación a las respuestas del código.
arcyqwerty

1
@test: length()devuelve un size_t, no un int. erase()toma un size_type, no un int. La función probablemente fallará si se encuentran dos espacios consecutivos ya que el índice siempre se incrementa. Si se elimina un espacio, el bucle leerá más allá de los límites de la cadena. Probablemente debería eliminar esta respuesta, ya que necesita mucha ayuda.
jww

-3

Me temo que es la mejor solución que se me ocurre. Pero puede usar reserve () para preasignar la memoria mínima requerida de antemano para acelerar un poco las cosas. Terminará con una nueva cadena que probablemente será más corta pero que ocupará la misma cantidad de memoria, pero evitará reasignaciones.

EDITAR: Dependiendo de su situación, esto puede generar menos gastos generales que los personajes confusos.

Debe probar diferentes enfoques y ver qué es lo mejor para usted: es posible que no tenga ningún problema de rendimiento.


remove_if hace como máximo una copia de cada valor. Entonces, realmente no hay tanta sobrecarga en relación con lo que hay que hacer.
Matt Price
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.