Biblioteka boost Tokenizer zapewnia elastyczny i łatwy w użyciu mechanizm dzielenia dowolnych łańcuchów znakowych na serię podciągów (tokens), grup znaków o podanych cechach. Biblioteka umożliwia wybór metody podziału łańcucha poprzez parametryzowane funktory TokenizerFunction
.
Powyższa klasa umożliwia widok na sekwencję znaków jak na kontener zawierający podciągi. Dostęp do podciągów zawartych w takim kontenerze zapewniony jest za pomocą iteratorów zdefiniowanych w bibliotece. Klasa tokenizer
jest klasą szablonową pozwalającą tworzyć obiekty dzielące sekwencje znakowe określonego typu według określonego sposobu podziału. Warto zauważyć,że podany łańcuch znakowy nie jest dzielony w czasie inicjalizacj obiektu, lecz na żądanie.
template < class TokenizerFunc = char_delimiters_separator<char>, class Iterator = std::string::const_iterator, class Type = std::string > class tokenizer
Parametry szablonu:
Prosty przykład użycia biblioteki:
#include<iostream> #include<boost/tokenizer.hpp> #include<string> using namespace std; using namespace boost; string str = "To jest, przyklad"; int main(){ //utorzenie domyślnego obiektu klasy tokenizer, w którym ciąg znaków string //dzielony jest na podstawie odstępów i znaków interpunkcyjnych tokenizer<> t(s); //dostęp do pojedyńczych tokenówjest realizowany przy użyciu iteratorów for(tokenizer<>::iterator beg=t.begin(); beg!=t.end();++beg){ cout << *beg << "\n"; } return 0; }
Wynikiem działania programu będzie sekwencja:
To jest przyklad
Lista konstruktorów oraz funkcji składowych:
//konstuktory tokenizer(Iterator first, Iterator last,const TokenizerFunc& f = TokenizerFunc()) template<class Container> tokenizer(const Container& c,const TokenizerFunc& f = TokenizerFunc()) //fukcja zmieniająca iteratory wskazujące na początek i za koniec sekwencji na nowe void assign(Iterator first, Iterator last) //fukcja zmieniająca iteratory wskazujące na początek i za koniec sekwencji oraz funkce podziału na nowe void assign(Iterator first, Iterator last, const TokenizerFunc& f) //fukcja zmieniająca kontener przechowujący sekwencję na nowy template<class Container> void assign(const Container& c) //fukcja zmieniająca kontener przechowujący sekwencję oraz funkcję podziału na nowe template<class Container> void assign(const Container& c, const TokenizerFunc& f) //iterator wskazujący na pierwszy podciąg iterator begin() const //iterator wskazujący za ostatni podciąg iterator end() const /* c - kontener zawierający sekwencję do podziału * f - funktor służący do podziału sekwencji * first - iteraor wskazujący na początek dzielonej sekwencji * last - iteraor wskazujący za dzieloną sekwencję */
Klasa zapewnia dostęp do podciągów dzielonej sekwencji jak przy użyciu zeykłego iteratora.
template < class TokenizerFunc = char_delimiters_separator<char>, class Iterator = std::string::const_iterator, class Type = std::string > class token_iterator_generator
Parametry szablonu:
W celu utorzenia iteratora musimy podać iterator wskazujący na początek dzielonej sekwencji begin
, iterator wskazujący dokładnie za dzieloną sekwencję end
oraz funkcję podziału sekwencji fun
.
template<class Type, class Iterator, class TokenizerFunc> typename token_iterator_generator<TokenizerFunc,Iterator,Type>::type make_token_iterator(Iterator begin, Iterator end,const TokenizerFunc& fun)
Przykład użycia przy wykorzystaniu funktora offset_separator
(opisanego dalej) dzielącego łańcuch znakowy na podciągi o określonej długości.
#include<iostream> #include<boost/token_iterator.hpp> #include<string> using namespace std; using namespace boost; string s = "12252001"; int offsets[] = {2,2,4}; int main(){ offset_separator f(offsets, offsets+3); typedef token_iterator_generator<offset_separator>::type Iter; Iter beg = make_token_iterator<string>(s.begin(),s.end(),f); Iter end = make_token_iterator<string>(s.end(),s.end(),f); for(;beg!=end;++beg){ cout << *beg << "\n"; } return 0; }
TokenizerFunction jest funktorem, którego zadaniem jest dzielenie podanej sekwencji znaków dopóki zostanie znaleziony dokładnie jeden podciąg lub osiągnięty koniec sekwencji. Następnie uaktualnia podciąg i informuje o położeniu w sekwencji elementu znajdującgo się dokładnie za za znalezionym podciągiem.
Biblioteka zawiera trzy klasy funktorów TokenizerFunction:
Klasa char_separator dzieli sekwencje znaków w sposób podobny do funkcji strtok()
używając w tym celu określonych znaków rozdzielających. Klasa ta jest używana w połączeniu z token_iterator
oraz tokenizer
w celu podziału na podciągi.
Funkcja strtok()
po dokonaniu podziału sekwencji nie umieszcza znaków rodzielających poszczególne podciągi. Jednak czasami okazuje się przydatnym posiadanie znaków rozdzielających pojawiających się w wyjściowej sekwencji podciągów, dlatego char_separator
zapewnia takie rozwiązanie.
Kiedy dwa znaki rozdzielające znajdują sie w sekwencji jeden za drugim. funkcja strtok()
pomija je, natomiast char_separator
pozwala również w takiej sytuacji na utworzenie pustego podciągu, w zależności od wyboru.
Poniższy przykład pokazuje jak zastąpić funkcję strtok()
za pomocą char_separator
. Określone są trzy znaki rozdzielające, które nie pojawią się w wyjściowych podciągach, puste podciągi będą ignorowane.
#include <iostream> #include <boost/tokenizer.hpp> #include <string> using namespace std; using namespace boost; string str = ";;Hello|world||-foo--bar;yow;baz|"; int main() { typedef tokenizer<boost::char_separator<char> > tokenizer; char_separator<char> sep("-;|"); //utworzenie funktora z określonymi znakami rozdzielającymi tokenizer tokens(str, sep); for (tokenizer::iterator tok_iter = tokens.begin(); tok_iter != tokens.end(); ++tok_iter){ std::cout << "<" << *tok_iter << "> "; } return 0; }
Wynikiem działania programu będzie sekwencja:
<Hello> <world> <foo> <bar> <yow> <baz>
Zmiana argumentów konstruktora funktora na:
boost::char_separator<char> sep("-;", "|", boost::keep_empty_tokens);
Wynikiem powyżej modyfikacji są puste podciągi oraz podciągi zawierające znak rozdzielający „|”, co obrazuje wynik działania programu:
<> <> <Hello> <|> <world> <|> <> <|> <> <foo> <> <bar> <yow> <baz> <|> <>
Lista konstruktorów oraz funkcji składowych:
//kostruktor tworzący obiekt char_separator, który może być następnie użyty do utworzenie token_iterator albo tokenizer //w celu podziału sekwencji na podciągi. Argumenty dropped_delims i kept_delims określają kolejno odrzucane i zachowywane //znaki rozdzielające. Jeżeli empty_tokens ma przypisane drop_empty_tokens, to puste podciągi będą odrzucane, a w wypadku //keep_empty_tokens będą zachowywane. explicit char_separator(const Char* dropped_delims, const Char* kept_delims = "", empty_token_policy empty_tokens = drop_empty_tokens) //konstruktor bezargumentowy, który tworzy obiekt w którym funkcja std::isspace() służy do identyfikacji odrzucanych znaków, //a funkcja std::ispunct() do identyfikacji zachowyanych znaków rozdielających. Puste podciągi są odrzucane. explicit char_separator() //funkcja wywoływana przez token_iterator w celu podziału sekwencji template <typename InputIterator, typename Token> bool operator()(InputIterator& next, InputIterator end, Token& tok)
Klasa escaped_list_separator
jest jedną z implementacji funktora TokenizerFunction. escaped_list_separator
formatuje dane typu csv
(Comma Separated Values
- wartości rozdzielone przecinkiem). Poniższy przykład obrazuje format, w którym użyto domyślnych znaków separatora, cytowania oraz znaku przywracającego znaczenie.
Pole 1,Pole 2,Pole 3
Pole 1,„Pole2, z przecinkiem”,Pole3
Pole1,Pole2 z\„otoczony cytowaniem\”,Pole3
Pole1, Pole2 z \n nowa linią,Pole3
Pole1, Pole2 z otoczonym \\,Pole3
Pola są domyślnie oddzielane przez przecinki. W celu wstawienia przecinka do pola, należy otoczyć go cytowaniem. Sekwencje trzech znaków przywracających znaczenie są wspierane.
Przykład użycia:
#include<iostream> #include<boost/tokenizer.hpp> #include<string> using namespace std; using namespace boost; string s = "Pole1,\"wstawianie cytowania dookola pola umozliwia, uzywanie przecinkow\",Pole3"; int main(){ tokenizer<escaped_list_separator<char> > tok(s); for(tokenizer<escaped_list_separator<char> >::iterator beg=tok.begin(); beg!=tok.end();++beg){ cout << *beg << "\n"; } return 0; }
Wynikiem działania programu będzie sekwencja:
Pole1 wstawianie cytowania dookola pola umozliwia, uzywanie przecinkow Pole3
Klasa escaped_list_separator
posiada dwa następujące konstruktory:
explicit escaped_list_separator(Char e = '\\', Char c = ',',Char q = '\"')
Parametry konstruktora:
escaped_list_separator(string_type e, string_type c, string_type q):
Parametry konstruktora:
Klasa offset_separator
jest kolejną z implementacji funktora TokenizerFunction, która może być użyta w celu podziału sekwencji na podciągi. offset_separator
dzieli sekwencję znaków char
na łańcuchy znakowe o określonej długości bazując na zdefiniowanych przesunięciach.
Poniższy przykład dzieli sekwencję „12252001” przy użyciu przesunięc(2,2,4) na podciągi 12 25 2001:
#include<iostream> #include<boost/tokenizer.hpp> #include<string> using namespace std; using namespace boost; string s = "12252001"; int offsets[] = {2,2,4}; int main(){ offset_separator f(offsets, offsets+3); tokenizer<offset_separator> tok(s,f); for(tokenizer<offset_separator>::iterator beg=tok.begin(); beg!=tok.end();++beg){ cout << *beg << "\n"; } return 0; }
Klasa offset_separator
posiada tylko jeden użyteczny konstruktor:
template<typename Iter> offset_separator(Iter begin,Iter end,bool bwrapoffsets = true, bool breturnpartiallast = true)
Parametry konstruktora:
int
true
, czy użyte tylko raz false
true
, czy odrzucany false