Mai mult
Cum pot repeta peste cuvintele dintr-un șir?
Am'm încercarea de a repeta peste cuvintele dintr-un șir.
Șirul poate fi presupus a fi compus din cuvinte separate prin spatii.
Rețineți că m-am'm nu este interesat în șir C funcții sau ca un fel de personaj de manipulare/de acces. De asemenea, vă rugăm să dați prioritate eleganta peste eficiență în răspunsul dumneavoastră.
Cea mai bună soluție pe care o am acum este:
#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);
}
Există un mod mai elegant de a face acest lucru?
2885
76
Eu folosesc acest lucru pentru a împărți șirul de un delimitator. Prima plasează rezultatele într-un pre-construite vector, cea de-a doua returnează un vector nou.
Rețineți că această soluție nu sări gol jetoane, astfel încât următoarele 4 elemente, dintre care unul este gol:
Pentru ce-l's valoare, aici's un alt mod de a extrage jetoane dintr-un șir de intrare, bazându-se doar pe standard, facilități de bibliotecă. L's un exemplu de putere si eleganta spatele design-ul din STL.
În loc de copierea extras jetoane la un flux de ieșire, s-ar putea introduceți-le într-un recipient, folosind același generic ["copie"] (https://en.cppreference.com/w/cpp/algorithm/copy) algoritm.
... sau de a crea "vector" direct:
O posibilă soluție folosind Impuls ar putea fi:
Această abordare ar putea fi chiar mai repede decât
stringstream
abordare. Și din moment ce acesta este un șablon generic funcția poate fi folosit pentru a împărți alte tipuri de siruri de caractere (wchar, etc. sau UTF-8), folosind toate tipurile de delimitatori.Vezi documentația pentru detalii.
Pentru cei cu care nu sta bine să-și sacrifice toate eficiență pentru codul de dimensiunea și de a vedea "eficient" ca un tip de eleganta, următoarele ar trebui să atingă un loc dulce (și cred că modelul clasa container este o awesomely plus de eleganta.):
Eu de obicei aleg să folosească
std::vector<std::string> tipuri de ca al doilea parametru (
ContainerT)... dar lista<>
este mult mai rapid decâtvector<> pentru accesul direct nu este necesar, și puteți crea chiar propriile clasa string și de a folosi ceva de genul
std::list<subșir>"unde" subșir` nu face nici copii pentru o viteză incredibilă crește.L's mai mult decat dublu la fel de repede ca cel mai rapid tokenize pe această pagină și de aproape 5 ori mai repede decât altele. De asemenea, perfect cu tipul parametrilor puteți elimina toate șir și lista de exemplare suplimentare pentru a crește viteza.
În plus, acesta nu face (extrem de ineficient) întoarcere de rezultat, ci mai degrabă se trece la jetoane ca o referință, astfel, de asemenea, permițându-vă pentru a construi jetoane folosind apelurile multiple dacă ați dorit.
În cele din urmă vă permite să specificați dacă doriți să tăiați gol token-uri de rezultate, prin intermediul unei ultimul parametru opțional.
Tot ce trebuie e
std::string
... restul sunt opționale. Nu se folosesc fluxuri sau impuls de bibliotecă, dar este suficient de flexibil pentru a fi în măsură să accepte unele dintre aceste tipuri de externe în mod natural.Aici's o altă soluție. L's compact și suficient de eficiente:
Acesta poate fi ușor templatised să se ocupe șir separatoare, larg siruri de caractere, etc.
Rețineți că divizarea
"" rezultatele într-un singur șir gol și divizarea
","` (ie. sep) rezultatele în două șiruri goale.De asemenea, acesta poate fi extins cu ușurință pentru a sări gol jetoane:
Dacă divizarea unui șir la mai multe delimitatori în timp ce sărind peste gol jetoane este de dorit, această versiune poate fi folosit:
Acesta este modul meu preferat de a repeta printr-un șir. Poți să faci ce vrei pe cuvânt.
Acest lucru este similar cu Stiva Preaplin întrebare [Cum am tokenize un șir de caractere în C++?][1].
Îmi place următorul deoarece plasează rezultatele într-un vector, susține un șir ca un delim și oferă control asupra păstrând valorile goale. Dar, nu't arata la fel de bine atunci.
Desigur, pentru a Stimula are o
split()
, care funcționează parțial ca asta. Și, dacă prin 'white-space', tu chiar nu însemna orice tip de white-space, folosind Impuls's split cu is_any_of()` mare de lucrări.STL nu au o astfel de metodă disponibile deja.
Cu toate acestea, puteți utiliza fie C's
strtok()
funcție de utilizareastd::string::c_str()
membru, sau puteți scrie propriul. Aici este un exemplu de cod am găsit după o căutare rapidă pe Google ("STL șir split"):Preluat de pe: <http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++de Programare-HOWTO-7.html>
Dacă aveți întrebări cu privire la codul de probă, lăsați un comentariu și voi explica.
Și doar pentru că nu pune în aplicare o
typedef
numit iterator sau suprasarcină<<
operatorul nu înseamnă că este rău cod. Eu folosesc C funcții destul de frecvent. De exemplu,printf
șiscanf
atât sunt mai rapide decâtstd::cin
șistd::cout
(în mod semnificativ), defopen
sintaxa este mult mai prietenos pentru binar tipuri, și ele, de asemenea, tind să producă mai mici Fostele.Don't obține vândute pe acest "Eleganta peste performanta" afacere.
Aici este o funcție split că:
șablon vector split(const T & str, const T & delimitatori) { vector v; typename T::size_type start = 0; auto pos = str.find_first_of(delimitatori, începe); în timp ce(pos != T::onp) { dacă(pos != începe) // ignora gol jetoane v. emplace_back(str, start, pos - start); start = poz + 1; pos = str.find_first_of(delimitatori, începe); } dacă(începe < str.lungime()) // ignora delimitator de sfârșit v. emplace_back(str, start, str.lungime() - start); // adauga ceea ce's de stânga a șirului return v; }
Exemplu de utilizare:
Am 2 linii soluție la această problemă:
Încă un alt flexibil și rapid
Să-l folosească cu un vector de siruri de caractere (Edit: Deoarece cineva mi-a arătat să nu moștenească STL clase... hrmf ;) ) :
Ca's a! Și că's doar o modalitate de a folosi tokenizer, cum să contele de cuvinte:
Limitată de imaginația ;)
Aici's o soluție simplă care folosește numai standard regex bibliotecă
Regex argument permite verificarea pentru mai multe argumente (spații, virgule, etc.)
Eu, de obicei, doar verifica pentru a împărți pe spații și virgule, așa că am, de asemenea, această funcție implicită:
La
"[\\s]+" verificări pentru spații (
\s) si virgula (
,`).Notă, dacă doriți să împartă
wstring
în loc destring
,std::regex " la " std::wregex
sregex_token_iterator " la " wsregex_token_iterator
Rețineți, de asemenea, poate doriți să ia șir argumentul de referință, în funcție de compilator.
Folosind
std::stringstream
ca trebuie funcționează foarte bine, și de a face exact ceea ce ai vrut. Daca're în căutarea doar pentru mod diferit de a face lucrurile, deși, puteți utiliza [std::găsi()
][1]/[std::find_first_of()
][2] și [std::string::substr()
][3].Aici's un exemplu:
Dacă doriți să utilizați impuls, dar doriți să utilizați un șir întreg ca delimitator (în loc de personaje unice la fel ca în cele mai multe dintre cele propuse anterior soluții), puteți utiliza
boost_split_iterator
.Exemplu de cod, inclusiv convenabil șablon:
Există o funcție numită
strtok
.Heres un regex soluție care utilizează numai standard regex bibliotecă. (M-am'm un pic ruginit, deci nu pot fi câteva erori de sintaxă, dar cel puțin aceasta este ideea generală)
De stringstream poate fi convenabil dacă aveți nevoie pentru a analiza șirului de non-spațiu simboluri:
Până acum am folosit unul în [Boost][1], dar am nevoie de ceva care nu't depinde de el, așa că am ajuns la asta: