Obecnie używam następującego kodu do przycięcia wszystkich std::strings
programów w moich programach:
std::string s;
s.erase(s.find_last_not_of(" \n\r\t")+1);
Działa dobrze, ale zastanawiam się, czy są jakieś przypadki końcowe, w których może się nie powieść?
Oczywiście mile widziane są odpowiedzi z eleganckimi alternatywami, a także lewe wykończenia.
std::string
klasę, kiedy to takie funkcje sprawiają, że inne języki są tak przyjemne w użyciu (na przykład Python).Odpowiedzi:
EDYCJA Od wersji c ++ 17 niektóre części standardowej biblioteki zostały usunięte. Na szczęście, począwszy od c ++ 11, mamy lambdy, które są doskonałym rozwiązaniem.
Dzięki https://stackoverflow.com/a/44973498/524503 za wprowadzenie nowoczesnego rozwiązania.
Oryginalna odpowiedź:
Zwykle używam jednego z tych 3 do moich potrzeb przycinania:
Są dość zrozumiałe i działają bardzo dobrze.
EDYCJA : BTW, mam
std::ptr_fun
tam pomócstd::isspace
w jednoznacznym ustaleniu, ponieważ tak naprawdę istnieje druga definicja, która obsługuje ustawienia narodowe. To mogła być obsada tak samo, ale ja lubię to bardziej.EDYCJA : Aby odnieść się do niektórych komentarzy na temat akceptowania parametru przez odniesienie, modyfikowanie i zwracanie go. Zgadzam się. Implementacją, którą prawdopodobnie wolałbym, byłyby dwa zestawy funkcji, jeden na miejscu i jeden, który tworzy kopię. Lepszym zestawem przykładów byłoby:
Zachowuję jednak pierwotną odpowiedź powyżej w kontekście i w celu utrzymania wysokiej głosowanej odpowiedzi nadal dostępnej.
źródło
boost::trim
na rozwiązaniu problemu.Użycie algorytmów ciągu Boost byłoby najłatwiejsze:
str
jest teraz"hello world!"
. Jest teżtrim_left
itrim
, która przycina obie strony.Jeśli dodasz
_copy
sufiks do dowolnej z powyższych nazw funkcji, nptrim_copy
. Funkcja zwróci przyciętą kopię ciągu zamiast modyfikować ją przez odwołanie.Jeśli dodasz
_if
sufiks do dowolnej z powyższych nazw funkcji, np.trim_copy_if
Możesz przyciąć wszystkie znaki spełniające Twój predykat, w przeciwieństwie do samych białych znaków.źródło
Użyj następującego kodu, aby wyrównać (końcowe) spacje i znaki tabulacji w
std::strings
( ideone ):I żeby to zrównoważyć, dołączę również lewy kod wykończenia ( ideone ):
źródło
str.substr(...).swap(str)
jest lepiej. Zapisz zadanie.basic_string& operator= (basic_string&& str) noexcept;
?To, co robisz, jest dobre i solidne. Długo używałem tej samej metody i jeszcze nie znalazłem szybszej metody:
Dostarczając znaki, które mają zostać przycięte, masz elastyczność przycinania znaków spoza białych i wydajność przycinania tylko tych znaków, które chcesz przyciąć.
źródło
trim
, tzn.rtrim(ltrim(s, t), t)
Trochę późno na imprezę, ale nieważne. Teraz jest już C ++ 11, mamy lambdy i zmienne automatyczne. Tak więc moja wersja, która obsługuje również białe znaki i puste ciągi, to:
Moglibyśmy zrobić iterator do tyłu
wsfront
i użyć go jako warunku zakończenia w drugim,find_if_not
ale jest to przydatne tylko w przypadku łańcucha całkowicie białych znaków, a gcc 4.8 przynajmniej nie jest wystarczająco inteligentny, aby wywnioskować rodzaj iteratora do tyłu (std::string::const_reverse_iterator
) zauto
. Nie wiem, jak drogie jest tworzenie iteratora wstecznego, więc tutaj YMMV. Po tej zmianie kod wygląda następująco:źródło
std::isspace
:auto wsfront=std::find_if_not(s.begin(),s.end(),std::isspace);
candidate template ignored: couldn't infer template argument '_Predicate' find_if_not(_InputIterator __first, _InputIterator __last, _Predicate __pred)
Wypróbuj to, działa dla mnie.
źródło
str.find_last_not_of(x)
zwraca pozycję pierwszego znaku różną od x. Zwraca npos tylko wtedy, gdy żadne znaki nie pasują do x. W tym przykładzie, jeśli nie ma spacji, zwróci równowartośćstr.length() - 1
, dając w zasadziestr.erase((str.length() - 1) + 1).
To znaczy, chyba że się mylę.std::string&
.Podoba mi się rozwiązanie tzamana, jedynym problemem jest to, że nie przycina ciągu zawierającego tylko spacje.
Aby poprawić tę 1 wadę, dodaj str.clear () pomiędzy 2 liniami trymera
źródło
ltrim
anirtrim
tak.std::stringstream
.http://ideone.com/nFVtEo
źródło
it
), i odwrotnie: pozycję znaku, po której są tylko spacje (rit
) - po tym zwraca nowo utworzony ciąg == kopia części oryginalnego ciągu - część oparta na tych iteratorach ...W przypadku pustego ciągu kod zakłada, że dodanie 1 do wartości
string::npos
0.string::npos
jest typustring::size_type
, który nie jest podpisany. Dlatego polegasz na przepełnieniu dodawania.źródło
1
dostd::string::npos
musi dać0
zgodnie zC++ Standard
. Jest to więc dobre założenie, na którym można absolutnie polegać.Zhakowany z Cplusplus.com
Działa to również w przypadku wartości zerowej. :-)
źródło
rtrim
nieltrim
W C ++ 17 możesz używać basic_string_view :: remove_prefix i basic_string_view :: remove_suffix :
Ładna alternatywa:
źródło
Moje rozwiązanie oparte na odpowiedzi @Bill the Lizard .
Zauważ, że te funkcje zwrócą pusty ciąg, jeśli ciąg wejściowy nie zawiera nic oprócz białych znaków.
źródło
Moja odpowiedź jest poprawą w stosunku do górnej odpowiedzi dla tego postu, która przycina znaki kontrolne oraz spacje (0-32 i 127 w tabeli ASCII ).
std::isgraph
określa, czy znak ma reprezentację graficzną, więc możesz użyć tego do zmiany odpowiedzi Evana, aby usunąć dowolny znak, który nie ma reprezentacji graficznej z żadnej strony łańcucha. Rezultatem jest znacznie bardziej eleganckie rozwiązanie:Uwaga: Alternatywnie powinieneś być w stanie użyć,
std::iswgraph
jeśli potrzebujesz obsługi szerokich znaków, ale będziesz musiał również edytować ten kod, aby umożliwićstd::wstring
manipulację, co jest czymś, czego nie przetestowałem (zobacz stronę referencyjną,std::basic_string
aby zbadać tę opcję) .źródło
Wraz z C ++ 11 pojawiło się również wyrażenie regularne moduł , który oczywiście może być użyty do przycinania spacji wiodących lub końcowych.
Może coś takiego:
źródło
Tego używam. Po prostu usuwaj przestrzeń z przodu, a następnie, jeśli coś pozostało, zrób to samo z tyłu.
źródło
źródło
Dla tego, co jest warte, oto implementacja wykończenia z myślą o wydajności. Jest znacznie szybszy niż wiele innych procedur przycinania, które widziałem w pobliżu. Zamiast używać iteratorów i std :: find, używa surowych ciągów c i indeksów. Optymalizuje następujące przypadki specjalne: łańcuch o rozmiarze 0 (nic nie rób), łańcuch bez białych znaków do przycinania (nic nie rób), łańcuch z tylko końcowymi białymi znakami do przycinania (wystarczy zmienić rozmiar łańcucha), łańcuch całkowicie białą spacją (wystarczy wyczyścić łańcuch) . I wreszcie, w najgorszym przypadku (łańcuch z wiodącymi białymi znakami), robi wszystko, aby wykonać wydajną konstrukcję kopii, wykonując tylko 1 kopię, a następnie przenosząc tę kopię w miejsce oryginalnego ciągu.
źródło
Może to być elegancki sposób na zrobienie tego
Funkcje pomocnicze są realizowane jako:
A kiedy już to wszystko umieścisz, możesz również napisać:
źródło
Implementacja Trim C ++ 11:
źródło
Myślę, że jeśli zaczniesz pytać o „najlepszy sposób” przycinania łańcucha, powiedziałbym, że dobrym rozwiązaniem byłoby:
Oczywiście istnieje zbyt wiele różnych sposobów podejścia do tego i na pewno zależy to od tego, czego naprawdę potrzebujesz. Jednak biblioteka standardowa C nadal ma bardzo przydatne funkcje w <string.h>, takie jak memchr. Jest powód, dla którego C jest nadal uważany za najlepszy język dla IO - jego stdlib to czysta wydajność.
źródło
Nie jestem pewien, czy twoje środowisko jest takie samo, ale w moim przypadku pusty ciąg znaków spowoduje przerwanie programu. Chciałbym owinąć to połączenie kasowania poleceniem if (! S.empty ()) lub użyć Boosta, jak już wspomniano.
źródło
Oto, co wymyśliłem:
Ekstrakcja strumienia automatycznie eliminuje białe spacje, więc działa to jak urok.
Całkiem czysty i elegancki, jeśli sam to powiem. ;)
źródło
Przyczyniając się do rozwiązania mojego problemu z hałasem.
trim
domyślnie tworzy nowy ciąg i zwraca zmodyfikowanytrim_in_place
ciąg, jednocześnie modyfikując przekazany ciąg. Tatrim
funkcja obsługuje semantykę przenoszenia c ++ 11.źródło
Można to zrobić prościej w C ++ 11 dzięki dodaniu
back()
ipop_back()
.źródło
Oto moja wersja:
źródło
Powyższe metody są świetne, ale czasami chcesz użyć kombinacji funkcji do tego, co rutyna uważa za spacje. W takim przypadku używanie funktorów do łączenia operacji może być nieporządne, dlatego wolę prostą pętlę, którą mogę zmodyfikować dla wykończenia. Oto nieco zmodyfikowana funkcja przycinania skopiowana z wersji C tutaj na SO. W tym przykładzie przycinam znaki nie alfanumeryczne.
źródło
Oto prosta implementacja. Do tak prostej operacji prawdopodobnie nie powinieneś używać żadnych specjalnych konstrukcji. Wbudowana funkcja isspace () zajmuje się różnymi formami białych znaków, dlatego powinniśmy z niej skorzystać. Musisz również wziąć pod uwagę specjalne przypadki, w których łańcuch jest pusty lub po prostu kilka spacji. Przycinanie w lewo lub w prawo można uzyskać z następującego kodu.
źródło
Oto rozwiązanie łatwe do zrozumienia dla początkujących, którzy nie używają pisma
std::
wszędzie i jeszcze nie znająconst
poprawności,iterator
s, STLalgorithm
itp.Mam nadzieję, że to pomoże...
źródło
Ta wersja przycina wewnętrzne białe znaki i znaki niealfanumeryczne:
źródło
Jeszcze inna opcja - usuwa jedną lub więcej postaci z obu końców.
źródło