Supprimer les espaces de std :: string en C ++


222

Quelle est la meilleure façon de supprimer des espaces d'une chaîne en C ++? Je pourrais parcourir tous les caractères et créer une nouvelle chaîne, mais y a-t-il une meilleure façon?

Réponses:


257

La meilleure chose à faire est d'utiliser l'algorithme remove_ifet isspace:

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

Maintenant, l'algorithme lui-même ne peut pas changer le conteneur (seulement modifier les valeurs), donc il mélange réellement les valeurs autour et renvoie un pointeur vers l'endroit où la fin devrait être maintenant. Nous devons donc appeler string :: erase pour modifier réellement la longueur du conteneur:

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

Nous devons également noter que remove_if fera au plus une copie des données. Voici un exemple d'implémentation:

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
Parce que 'isspace' a des surcharges, vous devrez probablement qualifier le code générique pour utiliser :: isspace (l'implémentation C qui ne prend pas de paramètres régionaux) ou être accueilli avec des erreurs d'instanciation de modèle cryptique.
Bklyn

4
Tous - méfiez-vous de la méthode ci-dessus (les deux lignes simples, pas la version basée sur des modèles, bien qu'elle puisse avoir le même problème). Je l'ai utilisé dans un projet sans réaliser qu'il n'est pas toujours correct. Par exemple, si vous lui passez la chaîne "1 + 1", elle renvoie "1 + 11". Je suis passé à la méthode de @rupello ci-dessous et cela a bien fonctionné dans ce cas. Bon codage!
JoeB

6
@Joe La réponse mentionne explicitement que vous devez appeler eraseaprès. Cela retournera le résultat correct.
Konrad Rudolph

31
-1 cette utilisation de isspaceest UB pour tous les jeux de caractères sauf ASCII 7 bits d'origine. C99 §7.4 / 1. cela ne me surprend pas qu'il ait été surévalué à hauteur de 71 voix à l'heure actuelle, bien qu'il s'agisse de très mauvais conseils.
Bravo et hth. - Alf

16
Pour répéter, le code de cette réponse transmet des valeurs négatives (différentes de EOF) à isspace, pour tous les caractères non ASCII, avec le choix de signature par défaut en pratique pour char. Il a donc un comportement indéfini . Je le répète parce que je soupçonne une tentative délibérée de noyer ce fait dans le bruit.
Bravo et hth. - Alf

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

31
Mon vote positif pour l'idiome d'effacement / suppression canonique. Peut être transformé en un liner: str.erase (std :: remove (str.begin (), str.end (), ''), str.end ());
Bklyn

11
Remarque: Vous devez inclure <algorithm>pour que cela fonctionne.
Tara

37

De gamedev

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

22
Cela ne compilera pas sur les implémentations conformes aux normes en raison des surcharges locales de std :: isspace. Vous devrez utiliser :: isspace ou effectuer des machinations illisibles avec std :: bind2nd. Le code générique n'est-il pas beau?
Bklyn

Notez également que si l'un des caractères est négatif (par exemple un caractère UTF8 lorsque le caractère est signé), l'utilisation de ::isspaceest UB.
Martin Bonner soutient Monica

30

Pouvez-vous utiliser Boost String Algo? http://www.boost.org/doc/libs/1_35_0/doc/html/string_algo/usage.html#id1290573

erase_all(str, " "); 

3
C'est plus lent que remove_if(str.begin(), str.end(), isspace);celui mentionné par Matt Price. Je ne sais pas pourquoi. En fait, tous les éléments boost, qui ont des alternatives STL, sont plus lents que ceux gcc correspondants (tous ceux que j'ai testés). Certains d'entre eux sont extrêmement lents! (jusqu'à 5 fois dans les insertions unordered_map) C'est peut-être à cause du cache CPU de l'environnement partagé ou quelque chose comme ça.
Etherealone

16

Pour le découpage, utilisez des algorithmes de chaîne boost :

#include <boost/algorithm/string.hpp>

using namespace std;
using namespace boost;

// ...

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

15

Vous pouvez utiliser cette solution pour supprimer un caractère:

#include <algorithm>
#include <string>
using namespace std;

str.erase(remove(str.begin(), str.end(), char_to_remove), str.end());

1
#include <string.h> utilisant l'espace de noms std;
slackmart

Cette solution est correcte pour moi. Celui du haut ne l'est pas.
Jason Liu

1
l'utilisation de namespace std doit être évitée. stackoverflow.com/questions/1452721/…
infinitezero

12

Salut, tu peux faire quelque chose comme ça. Cette fonction supprime tous les espaces.

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

J'ai fait une autre fonction, qui supprime tous les espaces inutiles.

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

utilise le:

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

7

Si vous voulez le faire avec une macro simple, en voici une:

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

Cela suppose que vous avez fait #include <string> bien sûr.

Appelez-le ainsi:

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

5
pourquoi utiliseriez-vous une macro pour cela?
dani

1
Moins de frappe au clavier pour une tâche courante.
Volomike

3
Tout aussi court pour le site d'appel appelle une fonction prenant une référence de valeur à une chaîne. Les macros peuvent avoir des comportements surprenants interagissant avec leurs arguments (en particulier avec des effets secondaires), mais pire, si elles sont impliquées dans une erreur, leurs noms n'apparaissent pas dans les messages du compilateur, leur implémentation le fait.
Chris Uzdavinis

2

J'ai utilisé le travail ci-dessous pendant longtemps - je ne suis pas sûr de sa complexité.

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

lorsque vous voulez supprimer du caractère ' 'et certains par exemple - utiliser

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

De même, augmentez simplement le ||nombre de caractères que vous souhaitez supprimer n'est pas 1

mais comme mentionné par d'autres, l'effacement de l'idiome semble également correct.


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

    return newWord;
}

Ce code prend essentiellement une chaîne et parcourt chaque caractère qu'il contient. Il vérifie ensuite si cette chaîne est un espace blanc, si ce n'est pas le cas, le caractère est ajouté à une nouvelle chaîne.


1
   #include <algorithm>
   using namespace std;

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

La source:

Référence tirée de ce forum.


1
Cela n'ajoute vraiment rien de plus que cette réponse ne le fait déjà. Y a-t-il plus d'explications ou de détails que vous pourriez ajouter pour rendre votre réponse de meilleure qualité et mériter d'être conservée sur cette question?
Das_Geek

Je pense que c'est plus simple , car cela fait la même chose dans une déclaration.
John

2
Génial! Mettez ensuite ce raisonnement comme explication directement dans votre réponse . La question d'origine date de plus de onze ans , et sans justification, votre réponse pourrait être considérée comme du bruit par rapport aux autres réponses acceptées et bien notées. Cette explication vous aidera à éviter que votre réponse ne soit supprimée.
Das_Geek

Ce serait bien, mais je ne pouvais pas comprendre comment je devrais mettre cela dans ma réponse ... que ma réponse est meilleure que cette réponse . ? Ce serait un grand plaisir si vous pouviez modifier ma réponse.
John

2
Malheureusement, la modification de votre réponse pour ajouter ce contenu moi-même irait à l'encontre des directives de modification , et ma modification serait probablement refusée ou annulée plus tard. Vous pouvez utiliser le premier lien de ce commentaire pour modifier vous-même la réponse. Il est tout à fait acceptable d'affirmer que vous pensez que votre réponse est meilleure qu'une autre et de la justifier. La communauté décidera si vous avez raison en votant pour ou contre.
Das_Geek

0

En C ++ 20, vous pouvez utiliser la fonction gratuite std :: erase

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

Exemple complet:

#include<string>
#include<iostream>

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

J'imprime | de sorte qu'il est évident que l'espace au début est également supprimé.

remarque: cela supprime uniquement l'espace, pas tous les autres caractères possibles qui peuvent être considérés comme des espaces, voir https://en.cppreference.com/w/cpp/string/byte/isspace


0

Supprime tous les caractères d'espacement tels que les tabulations et les sauts de ligne (C ++ 11):

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

Pourquoi recommanderiez-vous cette approche à la réponse acceptée de @ Matt-Price il y a plus de dix ans?
Jeremy Caney

Que toutes les solutions soient présentées ici. Peut-être que quelqu'un aura besoin de cette solution.
AnselmRu

Je ne m'oppose pas à cela. Je dis qu'il est plus facile pour les gens d'évaluer différentes approches en expliquant les différences et les scénarios pour lesquels elles pourraient être mieux adaptées.
Jeremy Caney

1
Cette solution n'est probablement pas la plus économique, mais elle vous permet de vous débarrasser de tous les caractères d' espacement '\ s', pas seulement des espaces ''.
AnselmRu

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

sortie: 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
Il est généralement préférable d'ajouter une brève explication pour coder les réponses.
arcyqwerty

1
@test - length()renvoie un size_t, pas un int. erase()prend un size_type, pas un int. La fonction échouera probablement si deux espaces consécutifs sont rencontrés car l'index est toujours incrémenté. Si un espace est supprimé, la boucle lira au-delà des limites de la chaîne. Vous devriez probablement supprimer cette réponse car elle a besoin de beaucoup d'aide.
jww

-3

J'ai bien peur que ce soit la meilleure solution à laquelle je puisse penser. Mais vous pouvez utiliser reserve () pour pré-allouer la mémoire minimale requise à l'avance pour accélérer un peu les choses. Vous vous retrouverez avec une nouvelle chaîne qui sera probablement plus courte mais qui occupe la même quantité de mémoire, mais vous éviterez les réallocations.

EDIT: Selon votre situation, cela peut entraîner moins de frais généraux que les personnages enchevêtrés.

Vous devriez essayer différentes approches et voir ce qui vous convient le mieux: il se peut que vous n'ayez aucun problème de performances.


remove_if fait au plus une copie de chaque valeur. Il n'y a donc vraiment pas beaucoup de frais généraux par rapport à ce qui doit être fait.
Matt Price
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.