Entfernen Sie Leerzeichen aus std :: string in C ++

222

Was ist die bevorzugte Methode zum Entfernen von Leerzeichen aus einer Zeichenfolge in C ++? Ich könnte alle Zeichen durchlaufen und eine neue Zeichenfolge erstellen, aber gibt es einen besseren Weg?

Steve Hanov
quelle

Antworten:

257

Am besten verwenden Sie den Algorithmus remove_ifund den isspace:

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

Jetzt kann der Algorithmus selbst den Container nicht mehr ändern (nur die Werte ändern), sodass die Werte tatsächlich gemischt werden und ein Zeiger darauf zurückgegeben wird, wo das Ende jetzt sein sollte. Wir müssen also string :: erase aufrufen, um die Länge des Containers tatsächlich zu ändern:

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

Wir sollten auch beachten, dass remove_if höchstens eine Kopie der Daten erstellt. Hier ist eine Beispielimplementierung:

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;
}
Matt Price
quelle
54
Da 'isspace' überladen ist, müssen Sie wahrscheinlich den generischen Code für die Verwendung von :: isspace (die C-Implementierung, die kein Gebietsschema verwendet) qualifizieren oder mit Fehlern bei der Instanziierung kryptischer Vorlagen begrüßt werden.
Bklyn
4
Seien Sie vorsichtig mit der oben genannten Methode (Die beiden einzelnen Zeilen, nicht die Vorlagenversion, obwohl sie möglicherweise das gleiche Problem haben). Ich habe es in einem Projekt verwendet, ohne zu bemerken, dass es nicht immer korrekt ist. Wenn Sie beispielsweise die Zeichenfolge "1 + 1" übergeben, wird "1 + 11" zurückgegeben. Ich habe unten auf die Methode von @rupello umgestellt und es hat in diesem Fall gut funktioniert. Viel Spaß beim Codieren!
JoeB
6
@ Joe In der Antwort wird ausdrücklich erwähnt, dass Sie erasedanach anrufen müssen . Das wird das richtige Ergebnis zurückgeben.
Konrad Rudolph
31
-1 Diese Verwendung von isspaceist UB für alle Zeichensätze mit Ausnahme des ursprünglichen 7-Bit-ASCII. C99 §7.4 / 1. es überrascht mich nicht , dass es inzwischen mit 71 Stimmen bewertet wurde, obwohl es ein sehr schlechter Rat ist.
Prost und hth. - Alf
16
Nur zur Wiederholung: Der Code in dieser Antwort übergibt negative Werte (die sich von EOF unterscheiden) an isspacealle Nicht-ASCII-Zeichen mit der in der Praxis standardmäßigen Auswahl der Vorzeichen für char. Somit hat es undefiniertes Verhalten . Ich wiederhole es, weil ich einen absichtlichen Versuch vermute, diese Tatsache in Lärm zu ertränken.
Prost und hth. - Alf
100
std::string::iterator end_pos = std::remove(str.begin(), str.end(), ' ');
str.erase(end_pos, str.end());
Arno
quelle
31
Meine Gegenstimme für die kanonische Lösch- / Entfernungssprache. Kann zu einem Einzeiler gemacht werden: str.erase (std :: remove (str.begin (), str.end (), ''), str.end ());
Bklyn
11
Hinweis: Damit <algorithm>dies funktioniert, müssen Sie einschließen .
Tara
37

Von Gamedev

string.erase(std::remove_if(string.begin(), string.end(), std::isspace), string.end());
Rupello
quelle
22
Dies wird bei standardkonformen Implementierungen nicht kompiliert, da std :: isspace das Gebietsschema überlastet. Sie müssen :: isspace verwenden oder einige unlesbare Bearbeitungen mit std :: bind2nd durchführen. Ist generischer Code nicht schön?
Bklyn
Beachten Sie auch, dass wenn eines der Zeichen negativ ist (z. B. ein UTF8-Zeichen, wenn das Zeichen signiert ist), ::isspaceUB verwendet wird.
Martin Bonner unterstützt Monica
30

Können Sie Boost String Algo verwenden? http://www.boost.org/doc/libs/1_35_0/doc/html/string_algo/usage.html#id1290573

erase_all(str, " "); 
Nemanja Trifunovic
quelle
3
Es ist langsamer als das remove_if(str.begin(), str.end(), isspace);, was Matt Price erwähnt hat. Ich weiß nicht warum. Tatsächlich sind alle Boost-Sachen, die STL-Alternativen haben, langsamer als die entsprechenden gcc-Sachen (alle, die ich getestet habe). Einige von ihnen sind immens langsamer! (bis zu 5 Mal in unordered_map-Einfügungen) Möglicherweise liegt es am CPU-Cache der gemeinsam genutzten Umgebung oder an etwas Ähnlichem.
Etherealone
16

Verwenden Sie zum Trimmen Boost-String-Algorithmen :

#include <boost/algorithm/string.hpp>

using namespace std;
using namespace boost;

// ...

string str1(" hello world! ");
trim(str1);      // str1 == "hello world!"
römisch
quelle
15

Mit dieser Lösung können Sie ein Zeichen entfernen:

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

str.erase(remove(str.begin(), str.end(), char_to_remove), str.end());
user2281802
quelle
1
#include <string.h> using Namespace std;
Slackmart
Diese Lösung ist für mich richtig. Das oberste ist nicht.
Jason Liu
1
Die Verwendung des Namespace std sollte vermieden werden. stackoverflow.com/questions/1452721/…
infinitezero
12

Hallo, so etwas kannst du machen. Diese Funktion löscht alle Leerzeichen.

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

Ich habe eine andere Funktion gemacht, die alle unnötigen Leerzeichen löscht.

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

benutze es:

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

Wenn Sie dies mit einem einfachen Makro tun möchten, ist hier eines:

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

Dies setzt #include <string>natürlich voraus, dass Sie dies getan haben .

Nennen Sie es so:

std::string sName = " Example Name ";
REMOVE_SPACES(sName);
printf("%s",sName.c_str()); // requires #include <stdio.h>
Volomike
quelle
5
Warum sollten Sie dafür ein Makro verwenden?
Dani
1
Weniger Tastatureingabe für eine häufige Aufgabe.
Volomike
3
Ebenso kurz für die Aufrufstelle ist das Aufrufen einer Funktion, die eine Wertreferenz auf eine Zeichenfolge verwendet. Makros können überraschende Verhaltensweisen aufweisen, die mit ihren Argumenten interagieren (insbesondere mit Nebenwirkungen). Schlimmer noch, wenn sie in einen Fehler verwickelt sind, werden ihre Namen nicht in Compilermeldungen angezeigt, ihre Implementierung jedoch.
Chris Uzdavinis
2

Ich habe die unten stehende Lösung lange verwendet - ich bin mir nicht sicher über ihre Komplexität.

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

wenn du Zeichen entfernen willst ' 'und manche zum Beispiel - verwenden

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

Erhöhen ||Sie ebenfalls einfach die Anzahl der Zeichen, die Sie entfernen möchten, nicht 1

aber wie von anderen erwähnt, scheint auch die Lösch-Entfernungs-Sprache in Ordnung zu sein.

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

    return newWord;
}

Dieser Code nimmt im Grunde eine Zeichenfolge und durchläuft jedes Zeichen darin. Anschließend wird geprüft, ob es sich bei dieser Zeichenfolge um ein Leerzeichen handelt. Wenn dies nicht der Fall ist, wird das Zeichen einer neuen Zeichenfolge hinzugefügt.

Knusprige Äpfel
quelle
1
   #include <algorithm>
   using namespace std;

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

Quelle:

Referenz aus diesem Forum.

John
quelle
1
Dies fügt nicht wirklich mehr hinzu als diese Antwort bereits. Gibt es weitere Erklärungen oder Details, die Sie hinzufügen könnten, um Ihre Antwort qualitativ hochwertiger und wertvoller zu gestalten?
Das_Geek
Ich denke, es ist einfacher , weil es in einer Aussage dasselbe tut.
John
2
Toll! Fügen Sie diese Argumentation dann direkt als Erklärung in Ihre Antwort ein . Die ursprüngliche Frage ist mehr als elf Jahre alt , und ohne Begründung könnte Ihre Antwort im Vergleich zu den anderen akzeptierten, gut bewerteten Antworten als Rauschen angesehen werden. Wenn Sie diese Erklärung haben, wird verhindert, dass Ihre Antwort entfernt wird.
Das_Geek
Das wäre gut, aber ich konnte nicht verstehen, wie ich das in meine Antwort einfügen sollte ... dass meine Antwort besser ist als diese Antwort . ? Es wäre mir eine große Freude, wenn Sie meine Antwort bearbeiten könnten .
John
2
Leider würde das Bearbeiten Ihrer Antwort , um diesen Inhalt selbst hinzuzufügen, gegen die Bearbeitungsrichtlinien verstoßen , und meine Bearbeitung würde wahrscheinlich abgelehnt oder später zurückgesetzt. Sie können den ersten Link in diesem Kommentar verwenden, um die Antwort selbst zu bearbeiten. Es ist völlig akzeptabel, zu behaupten, dass Ihre Antwort besser ist als eine andere, und dies zu begründen. Die Community entscheidet durch Up- oder Downvoting, ob Sie Recht haben.
Das_Geek
0

In C ++ 20 können Sie die freie Funktion std :: erase verwenden

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

Vollständiges Beispiel:

#include<string>
#include<iostream>

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

Ich drucke | so dass es offensichtlich ist, dass der Platz am Anfang auch entfernt wird.

Hinweis: Dadurch wird nur das Leerzeichen entfernt, nicht jedes andere mögliche Zeichen, das als Leerzeichen betrachtet werden kann (siehe https://en.cppreference.com/w/cpp/string/byte/isspace)

NoSenseEtAl
quelle
0

Entfernt alle Leerzeichen wie Tabulatoren und Zeilenumbrüche (C ++ 11):

string str = " \n AB cd \t efg\v\n";
str = regex_replace(str,regex("\\s"),"");
AnselmRu
quelle
Warum würden Sie diesen Ansatz gegenüber der von @ Matt-Price akzeptierten Antwort von vor über einem Jahrzehnt empfehlen?
Jeremy Caney
Lassen Sie alle Lösungen hier vorstellen. Vielleicht braucht jemand diese Lösung.
AnselmRu
Ich argumentiere nicht dagegen. Ich sage, machen Sie es den Menschen leichter, verschiedene Ansätze zu bewerten, indem Sie die Unterschiede erklären und für welche Szenarien sie möglicherweise besser geeignet sind.
Jeremy Caney
1
Wahrscheinlich ist diese Lösung nicht die wirtschaftlichste, aber Sie können alle Leerzeichen , nicht nur Leerzeichen, entfernen.
AnselmRu
0
  string str = "2C F4 32 3C B9 DE";
  str.erase(remove(str.begin(),str.end(),' '),str.end());
  cout << str << endl;

Ausgabe: 2CF4323CB9DE

Kerim FIRAT
quelle
-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
quelle
3
Es wird im Allgemeinen bevorzugt, dass Sie den Code-Antworten eine kurze Erklärung hinzufügen.
Arcyqwerty
1
@test - length()gibt a zurück size_t, nicht an int. erase()nimmt ein size_type, nicht ein int. Die Funktion schlägt wahrscheinlich fehl, wenn zwei aufeinanderfolgende Leerzeichen gefunden werden, da der Index immer inkrementiert wird. Wenn ein Leerzeichen entfernt wird, liest die Schleife über die Grenzen der Zeichenfolge hinaus. Sie sollten diese Antwort wahrscheinlich löschen, da sie viel Hilfe benötigt.
Jww
-3

Ich fürchte, es ist die beste Lösung, die ich mir vorstellen kann. Sie können jedoch Reserve () verwenden, um den minimal erforderlichen Speicher im Voraus vorab zuzuweisen, um die Dinge etwas zu beschleunigen. Am Ende erhalten Sie eine neue Zeichenfolge, die wahrscheinlich kürzer ist, aber dieselbe Menge an Speicherplatz beansprucht, aber eine Neuzuweisung vermeidet.

BEARBEITEN: Abhängig von Ihrer Situation kann dies weniger Aufwand verursachen als das Durcheinander von Zeichen.

Sie sollten verschiedene Ansätze ausprobieren und herausfinden, was für Sie am besten ist: Möglicherweise haben Sie überhaupt keine Leistungsprobleme.

Dave Van den Eynde
quelle
remove_if erstellt höchstens eine Kopie jedes Werts. Es gibt also wirklich nicht so viel Aufwand im Verhältnis zu dem, was getan werden muss.
Matt Price