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?

Steve Hanov
la source

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;
}
Prix ​​Matt
la source
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());
Arno
la source
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());
rupello
la source
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, " "); 
Nemanja Trifunovic
la source
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!"
romain
la source
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());
user2281802
la source
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;
}
ddacot
la source
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, " ", "+");
SudoBash
la source
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>
Volomike
la source
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.

RaGa__M
la source
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.

Pommes croquantes
la source
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.

John
la source
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

NoSenseEtAl
la source
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"),"");
AnselmRu
la source
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

Kerim FIRAT
la source
-1
string removespace(string str)
{    
    int m = str.length();
    int i=0;
    while(i<m)
    {
        while(str[i] == 32)
        str.erase(i,1);
        i++;
    }    
}
test c
la source
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.

Dave Van den Eynde
la source
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