Próbuję iterować słowa łańcucha.
Można założyć, że ciąg składa się ze słów oddzielonych spacją.
Zauważ, że nie interesują mnie funkcje łańcucha C ani tego rodzaju manipulacja / dostęp do znaków. W swojej odpowiedzi prosimy również o pierwszeństwo elegancji przed wydajnością.
Najlepszym rozwiązaniem, jakie mam teraz, jest:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main()
{
string s = "Somewhere down the road";
istringstream iss(s);
do
{
string subs;
iss >> subs;
cout << "Substring: " << subs << endl;
} while (iss);
}
Czy jest na to bardziej elegancki sposób?
while (iss) { string subs; iss >> subs; cout << "Substring: " << sub << endl; }
string sub; while (iss >> sub) cout << "Substring: " << sub << '\n';
Odpowiedzi:
Oto, co warto, oto inny sposób na wyodrębnienie tokenów z ciągu wejściowego, opierając się tylko na standardowych urządzeniach bibliotecznych. To przykład siły i elegancji stojących za stylistyką STL.
Zamiast kopiować wyodrębnione tokeny do strumienia wyjściowego, można wstawić je do kontenera, używając tego samego
copy
algorytmu ogólnego .... lub utwórz
vector
bezpośrednio:źródło
Używam tego do dzielenia łańcucha przez separator. Pierwszy umieszcza wyniki we wstępnie skonstruowanym wektorze, drugi zwraca nowy wektor.
Zwróć uwagę, że to rozwiązanie nie pomija pustych tokenów, więc poniższe znajdą 4 przedmioty, z których jeden jest pusty:
źródło
empty()
sprawdź:if (!item.empty()) elems.push_back(item)
->
?f(split(s, d, v))
przy jednoczesnym korzystaniu z wstępnie przydzielonego,vector
jeśli chcesz.Możliwym rozwiązaniem wykorzystującym Boost może być:
Takie podejście może być nawet szybsze niż
stringstream
podejście. A ponieważ jest to ogólna funkcja szablonu, może być używana do dzielenia innych typów ciągów (wchar itp. Lub UTF-8) przy użyciu wszelkiego rodzaju ograniczników.Szczegółowe informacje można znaleźć w dokumentacji .
źródło
źródło
getline
wwhile
stan np rozłamu przecinkami użytkuwhile(getline(ss, buff, ','))
.Dla tych, z którymi nie najlepiej jest poświęcić całą wydajność dla rozmiaru kodu i postrzegać „efektywny” jako rodzaj elegancji, poniższe elementy powinny trafić w dobre miejsce (i myślę, że klasa kontenera szablonów jest niesamowicie eleganckim dodatkiem):
Zwykle wybieram użycie
std::vector<std::string>
typów jako mojego drugiego parametru (ContainerT
) ... alelist<>
jest o wiele szybszy niż wvector<>
przypadku, gdy bezpośredni dostęp nie jest potrzebny, a nawet możesz stworzyć własną klasę łańcuchów i użyć czegoś takiego,std::list<subString>
gdziesubString
nie robi żadnych kopii z niewiarygodną prędkością wzrasta.Jest ponad dwukrotnie szybszy niż najszybszy tokenizuj na tej stronie i prawie 5 razy szybszy niż niektóre inne. Również dzięki idealnym typom parametrów możesz wyeliminować wszystkie kopie ciągów i list, aby zwiększyć prędkość.
Ponadto nie powoduje (wyjątkowo nieefektywnego) zwrotu wyniku, ale raczej przekazuje tokeny jako odniesienie, co pozwala również na budowanie tokenów przy użyciu wielu wywołań, jeśli chcesz.
Wreszcie pozwala określić, czy przycinać puste tokeny z wyników za pomocą ostatniego opcjonalnego parametru.
Wszystko czego potrzebuje to
std::string
... reszta jest opcjonalna. Nie używa strumieni ani biblioteki doładowania, ale jest wystarczająco elastyczny, aby naturalnie akceptować niektóre z tych obcych typów.źródło
typedef ContainerT Base; typedef typename Base::value_type ValueType; typedef typename ValueType::size_type SizeType;
nazwy pseudonimów : Następnie odpowiednio zastąpić typ_typu i typ_rozmiaru.trimEmpty = true
. Pamiętaj, że"abo"
w tej odpowiedzi nie jest ogranicznikiem, ale lista znaków ogranicznika. Łatwo byłoby zmodyfikować go tak, aby przyjmował pojedynczy ciąg znaków separatora (myślę, żestr.find_first_of
powinienem zmienićstr.find_first
, ale mogę się mylić ... nie mogę przetestować)Oto inne rozwiązanie. Jest kompaktowy i stosunkowo wydajny:
Może być łatwo szablonowany do obsługi separatorów strun, szerokich strun itp.
Zauważ, że dzielenie
""
powoduje pojedynczy pusty ciąg, a dzielenie","
(np. Sep) powoduje dwa puste ciągi.Można go również łatwo rozszerzyć, aby pomijać puste tokeny:
Jeśli pożądany jest podział łańcucha na wiele ograniczników podczas pomijania pustych tokenów, można użyć tej wersji:
źródło
To mój ulubiony sposób na iterację po łańcuchu. Możesz zrobić, co chcesz na słowo.
źródło
word
jakochar
?stringstream ss("Hello World, this is*@#&$(@ a string"); char c; while(ss >> c) cout << c;
Jest to podobne do pytania Przepełnienie stosu Jak tokenizować ciąg w C ++? .
źródło
Podobają mi się następujące, ponieważ umieszcza wyniki w wektorze, obsługuje ciąg jako separator i daje kontrolę nad utrzymywaniem pustych wartości. Ale to nie wygląda tak dobrze.
Oczywiście, Boost ma taki,
split()
który działa częściowo tak. A jeśli przez „białą spację”, naprawdę masz na myśli dowolny rodzaj białej spacji, użycie podziału Boostais_any_of()
działa świetnie.źródło
STL nie ma już takiej metody dostępnej.
Możesz jednak użyć
strtok()
funkcji C za pomocąstd::string::c_str()
członka lub możesz napisać własną. Oto przykładowy kod, który znalazłem po szybkim wyszukiwaniu w Google ( „Podział ciągu STL” ):Pobrano z: http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html
Jeśli masz pytania dotyczące próbki kodu, zostaw komentarz, a ja ci wyjaśnię.
I tylko dlatego, że nie implementuje on
typedef
zwanego iteratora lub przeciążenia,<<
operator nie oznacza, że jest to zły kod. Często używam funkcji C. Na przykład,printf
iscanf
oba są szybsze niżstd::cin
istd::cout
(znacząco),fopen
składnia jest o wiele bardziej przyjazna dla typów binarnych, a także mają tendencję do tworzenia mniejszych plików EXE.Nie daj się sprzedać w ramach oferty „Elegancja ponad wydajność” .
źródło
Oto funkcja podziału, która:
ignoruje puste tokeny (można je łatwo zmienić)
Przykładowe użycie:
źródło
Mam 2-liniowe rozwiązanie tego problemu:
Następnie zamiast drukowania możesz umieścić go w wektorze.
źródło
Kolejny elastyczny i szybki sposób
Aby użyć go z wektorem ciągów (Edytuj: Ponieważ ktoś wskazał, aby nie dziedziczyć klas STL ... hrmf;)):
Otóż to! A to tylko jeden ze sposobów korzystania z tokenizera, na przykład liczenie słów:
Ograniczona wyobraźnią;)
źródło
Appender
uwagi „Dlaczego nie powinniśmy dziedziczyć klasy po klasach STL?”Oto proste rozwiązanie, które korzysta tylko ze standardowej biblioteki wyrażeń regularnych
Argument regex pozwala na sprawdzenie wielu argumentów (spacje, przecinki itp.)
Zazwyczaj zaznaczam tylko podział na spacje i przecinki, więc mam również tę domyślną funkcję:
Do
"[\\s,]+"
sprawdza spacji (\\s
) i przecinków (,
).Uwaga: jeśli chcesz podzielić
wstring
zamiaststring
,std::regex
nastd::wregex
sregex_token_iterator
nawsregex_token_iterator
Uwaga: w zależności od kompilatora możesz również chcieć wziąć argument ciągu znaków przez odniesienie.
źródło
R"([\s,]+)"
.Używanie tego,
std::stringstream
co masz, działa doskonale i rób dokładnie to, co chciałeś. Jeśli jednak szukasz innego sposobu robienia rzeczy, możesz użyćstd::find()
/std::find_first_of()
istd::string::substr()
.Oto przykład:
źródło
prev_pos = pos += delimiter.length();
Jeśli chcesz użyć wzmocnienia, ale chcesz użyć całego łańcucha jako separatora (zamiast pojedynczych znaków, jak w większości wcześniej proponowanych rozwiązań), możesz użyć
boost_split_iterator
.Przykładowy kod zawierający wygodny szablon:
źródło
Oto rozwiązanie wyrażenia regularnego, które wykorzystuje tylko standardową bibliotekę wyrażeń regularnych. (Jestem trochę zardzewiały, więc może być kilka błędów składniowych, ale to przynajmniej ogólny pomysł)
źródło
Istnieje funkcja o nazwie
strtok
.źródło
strtok
pochodzi ze standardowej biblioteki C, a nie C ++. Nie jest bezpiecznie używać w programach wielowątkowych. Zmienia ciąg wejściowy.strtok
gdy inny wątek wciąż przetwarza, ten wskaźnik char zostanie zastąpiony, a następnie oba wątki będą miały niepoprawne wyniki. mkssoftware.com/docs/man3/strtok.3.aspStrumień ciągu może być wygodny, jeśli trzeba parsować ciąg za pomocą symboli spacji:
źródło
Do tej pory korzystałem z tego w Boost , ale potrzebowałem czegoś, co nie zależy od tego, więc doszedłem do tego:
Dobrą rzeczą jest to,
separators
że możesz przekazać więcej niż jedną postać.źródło
Rzuciłem własną za pomocą strtok i użyłem boosta do podzielenia łańcucha. Najlepszą metodą, jaką znalazłem, jest biblioteka C ++ String Toolkit Library . Jest niezwykle elastyczny i szybki.
Zestaw narzędzi ma znacznie większą elastyczność niż pokazuje ten prosty przykład, ale jego użyteczność w parsowaniu łańcucha na użyteczne elementy jest niesamowita.
źródło
Krótki i elegancki
może używać dowolnego łańcucha jako separatora, może być również używany z danymi binarnymi (std :: string obsługuje dane binarne, w tym wartości null)
za pomocą:
wynik:
źródło
Zrobiłem to, ponieważ potrzebowałem łatwego sposobu na podzielenie łańcuchów i łańcuchów opartych na c ... Mam nadzieję, że ktoś inny również może się przydać. Nie zależy też od tokenów i możesz używać pól jako ograniczników, co jest kolejnym kluczem, którego potrzebowałem.
Jestem pewien, że można wprowadzić ulepszenia, aby jeszcze bardziej poprawić jego elegancję i proszę zrobić to za wszelką cenę
StringSplitter.hpp:
StringSplitter.cpp:
Przykłady:
Wyjdzie:
To
jest przykład cstring
Aby zachować puste wpisy (domyślnie puste zostaną wykluczone):
Celem było uczynienie go podobnym do metody Split () C #, w której dzielenie łańcucha jest tak proste, jak:
Mam nadzieję, że ktoś inny uzna to za równie przydatne, co ja.
źródło
A co z tym:
źródło
Ta odpowiedź pobiera ciąg znaków i umieszcza go w wektorze ciągów. Korzysta z biblioteki doładowań.
źródło
Oto inny sposób na zrobienie tego ...
źródło
Lubię używać do tego zadania metod boost / regex, ponieważ zapewniają one maksymalną elastyczność przy określaniu kryteriów podziału.
źródło
Ostatnio musiałem podzielić słowo w wielbłądach na słowa podrzędne. Nie ma żadnych ograniczników, tylko górne znaki.
Na przykład dzieli to „AQueryTrades” na „A”, „Query” i „Trades”. Funkcja działa z wąskimi i szerokimi łańcuchami. Ponieważ szanuje obecną lokalizację, dzieli „RaumfahrtÜberwachungsVerordnung” na „Raumfahrt”, „Überwachungs” i „Verordnung”.
Uwaga
std::upper
powinna być naprawdę przekazana jako argument szablonu funkcji. Wtedy bardziej uogólnione z tej funkcji można podzielić na ograniczniki, takie jak","
,";"
lub" "
też.źródło
std::isupper
można je uznać za argument, a niestd::upper
. Po drugie umieśćtypename
przedString::const_iterator
.źródło
Korzystanie
std::string_view
irange-v3
biblioteka Erica Nieblera :https://wandbox.org/permlink/kW5lwRCL1pxjp2pW
Używając
for
pętli zakresu zamiastranges::for_each
algorytmu:źródło