Usuń spacje ze std :: string w C ++


222

Jaki jest preferowany sposób usuwania spacji z łańcucha w C ++? Mógłbym zapętlić wszystkie postacie i zbudować nowy ciąg, ale czy jest lepszy sposób?

Odpowiedzi:


257

Najlepiej jest użyć algorytmu remove_ifi isspace:

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

Teraz sam algorytm nie może zmienić kontenera (tylko modyfikować wartości), więc faktycznie przetasowuje wartości i zwraca wskaźnik do miejsca, w którym powinien być teraz koniec. Musimy więc wywołać string :: erase, aby faktycznie zmodyfikować długość kontenera:

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

Należy również pamiętać, że remove_if utworzy co najwyżej jedną kopię danych. Oto przykładowa implementacja:

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
Ponieważ „isspace” ma przeciążenia, prawdopodobnie będziesz musiał zakwalifikować ogólny kod do użycia :: isspace (implementacja C, która nie przyjmuje ustawień regionalnych) lub zostać przywitanym za pomocą tajemniczych błędów tworzenia szablonów.
Bklyn

4
Wszystko - bądź ostrożny z powyższą metodą (dwie pojedyncze linie, nie wersja z szablonem, chociaż może mieć ten sam problem). Użyłem go w projekcie, nie zdając sobie sprawy, że nie zawsze jest to poprawne. Na przykład, jeśli przekażesz ciąg „1 + 1”, zwróci „1 + 11”. Przełączyłem się na metodę @rupello poniżej i to zadziałało dobrze w tym przypadku. Miłego kodowania!
JoeB

6
@Joe W odpowiedzi wyraźnie wspomniano, że należy erasepóźniej zadzwonić . To zwróci poprawny wynik.
Konrad Rudolph

31
-1 to użycie isspacejest UB dla wszystkich zestawów znaków oprócz oryginalnego 7-bitowego ASCII. C99 § 7.4 / 1. to nie dziwi mnie, że to było upvoted w wysokości 71 głosami teraz, mimo że bardzo złe rady.
Pozdrawiam i hth. - Alf

16
Wystarczy powtórzyć, kod w tej odpowiedzi przekazuje wartości ujemne (inne niż EOF) do isspace, dla wszystkich znaków spoza ASCII, z domyślnym wyborem sygnatury w praktyce char. W ten sposób ma niezdefiniowane zachowanie . Powtarzam to, ponieważ podejrzewam celową próbę zatopienia tego faktu w hałasie.
Pozdrawiam i hth. - Alf

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

31
Moje głosowanie za kanonicznym wymazaniem / usunięciem idiomu. Może być przekształcony w jedną linijkę: str.erase (std :: remove (str.begin (), str.end (), ''), str.end ());
Bklyn

11
Uwaga: Musisz to uwzględnić, <algorithm>aby to działało.
Tara,

37

Od gamedev

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

22
Nie będzie się to kompilowało w implementacjach zgodnych ze standardami z powodu przeładowania lokalizacji przez std :: isspace. Musisz użyć :: isspace lub wykonać kilka nieczytelnych machinacji za pomocą std :: bind2nd. Czy ogólny kod nie jest piękny?
Bklyn

Zauważ też, że jeśli którykolwiek ze znaków jest ujemny (np. Znak UTF8 po podpisaniu znaku), użycie ::isspaceto UB.
Martin Bonner obsługuje Monikę

30

Czy możesz użyć Boost String Algo? http://www.boost.org/doc/libs/1_35_0/doc/html/string_algo/usage.html#id1290573

erase_all(str, " "); 

3
Jest wolniejszy niż wspomniany remove_if(str.begin(), str.end(), isspace);Matt Price. Nie wiem dlaczego. W rzeczywistości wszystkie elementy wspomagające, które mają alternatywy STL, są wolniejsze niż odpowiadające im gcc (wszystkie te, które testowałem). Niektóre z nich są znacznie wolniejsze! (do 5 razy we wstawkach unordered_map) Być może dzieje się tak z powodu pamięci podręcznej procesora w udostępnianym środowisku lub czegoś podobnego.
Etherealone



12

Cześć, możesz zrobić coś takiego. Ta funkcja usuwa wszystkie spacje.

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

Zrobiłem inną funkcję, która usuwa wszystkie niepotrzebne spacje.

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

Użyj tego:

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

7

Jeśli chcesz to zrobić za pomocą łatwego makra, oto jedno:

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

Zakłada się, że zrobiłeś #include <string> oczywiście.

Nazwij to tak:

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

5
dlaczego używałbyś do tego makra?
dani

1
Mniej pisania na klawiaturze dla typowego zadania.
Volomike,

3
Równie skrótem dla strony wywołującej jest wywołanie funkcji przyjmującej odwołanie do wartości do łańcucha. Makra mogą mieć zaskakujące zachowania wchodzące w interakcje z ich argumentami (szczególnie z efektami ubocznymi), ale gorzej, jeśli są zaangażowane w błąd, ich nazwy nie pojawiają się w komunikatach kompilatora, ich implementacja tak.
Chris Uzdavinis,

2

Długo korzystałem z poniższej metody - nie jestem pewien jej złożoności.

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

kiedy chcesz usunąć postać, ' 'a niektóre na przykład - użyć

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

podobnie po prostu zwiększ || liczbę, jeśli liczba znaków, które chcesz usunąć, nie wynosi 1

ale jak wspominają inni, idiom usuwania usuń również wydaje się w porządku.


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

    return newWord;
}

Ten kod w zasadzie pobiera ciąg znaków i iteruje wszystkie zawarte w nim znaki. Następnie sprawdza, czy ten ciąg jest białą spacją, jeśli nie jest, to znak jest dodawany do nowego ciągu.


1
   #include <algorithm>
   using namespace std;

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

Źródło:

Referencje zaczerpnięte z tego forum.


1
To tak naprawdę nie dodaje niczego więcej niż ta odpowiedź już. Czy możesz podać więcej wyjaśnień lub szczegółów, aby Twoja odpowiedź była lepsza i warta kontynuowania tego pytania?
Das_Geek

Myślę, że jest to prostsze , ponieważ robi to samo w jednym stwierdzeniu.
Jan

2
Wspaniały! Następnie umieść to rozumowanie jako wyjaśnienie bezpośrednio w swojej odpowiedzi . Pierwotne pytanie ma ponad jedenaście lat i bez uzasadnienia twoja odpowiedź może być postrzegana jako hałas w porównaniu z innymi zaakceptowanymi, dobrze ocenionymi odpowiedziami. Posiadanie takiego wyjaśnienia pomoże zapobiec usunięciu odpowiedzi.
Das_Geek

To byłby dobry , ale nie mogłem, że jak mam umieścić że na moją odpowiedź ... że moja odpowiedź jest lepsza niż ta odpowiedź . ? Z wielką przyjemnością zredagowałbyś moją odpowiedź.
Jan

2
Niestety edytowanie odpowiedzi w celu dodania tej treści byłoby niezgodne z wytycznymi dotyczącymi edycji , a moja edycja prawdopodobnie zostałaby odrzucona lub wycofana później. Możesz użyć pierwszego linku w tym komentarzu, aby samodzielnie edytować odpowiedź. Całkowicie dopuszczalne jest stwierdzenie, że uważasz, że twoja odpowiedź jest lepsza niż jakakolwiek inna, i uzasadnienie tego. Społeczność zdecyduje, czy masz rację, głosując w górę lub w dół.
Das_Geek

0

W C ++ 20 możesz używać darmowej funkcji std :: erase

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

Pełny przykład:

#include<string>
#include<iostream>

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

Drukuję | tak, że jest oczywiste, że przestrzeń na początku jest również usuwana.

Uwaga: usuwa to tylko spację, a nie każdą inną możliwą postać, którą można uznać za spację, patrz https://en.cppreference.com/w/cpp/string/byte/isspace


0

Usuwa wszystkie znaki spacji, takie jak tabulatory i podziały wierszy (C ++ 11):

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

Dlaczego poleciłbyś takie podejście zamiast zaakceptowanej odpowiedzi @ Matt-Price sprzed ponad dekady?
Jeremy Caney

Niech wszystkie rozwiązania zostaną tutaj przedstawione. Może ktoś będzie potrzebował tego rozwiązania.
AnselmRu

Nie sprzeciwiam się temu. Mówię, aby ułatwić ludziom ocenę różnych podejść, wyjaśniając różnice i jakie scenariusze mogą być bardziej odpowiednie.
Jeremy Caney

1
Prawdopodobnie to rozwiązanie nie jest najbardziej ekonomiczne, ale pozwala pozbyć się wszystkich białych znaków , a nie tylko spacji.
AnselmRu

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

wyjście: 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
Ogólnie zaleca się dodanie krótkiego wyjaśnienia do odpowiedzi na kod.
arcyqwerty

1
@test - length()zwraca a size_t, a nie an int. erase()bierze, a size_typenie int. Funkcja prawdopodobnie zawiedzie, jeśli napotkane zostaną dwie kolejne spacje, ponieważ indeks jest zawsze zwiększany. Jeśli jedna spacja zostanie usunięta, pętla będzie czytać poza granicami łańcucha. Prawdopodobnie powinieneś usunąć tę odpowiedź, ponieważ wymaga ona dużej pomocy.
jww

-3

Obawiam się, że to najlepsze rozwiązanie, jakie mogę wymyślić. Możesz jednak użyć funkcji replace (), aby wstępnie przydzielić wcześniej minimalną wymaganą pamięć, aby nieco przyspieszyć. Otrzymasz nowy ciąg znaków, który prawdopodobnie będzie krótszy, ale zajmuje tyle samo pamięci, ale unikniesz realokacji.

EDYCJA: W zależności od twojej sytuacji, może to powodować mniejsze obciążenie ogólne niż pomieszanie postaci.

Powinieneś wypróbować różne podejścia i przekonać się, co jest dla Ciebie najlepsze: możesz nie mieć żadnych problemów z wydajnością.


remove_if tworzy co najwyżej jedną kopię każdej wartości. Tak więc naprawdę nie ma tak dużego narzutu w stosunku do tego, co należy zrobić.
Matt Price
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.