Narzędzia użytkownika

Narzędzia witryny


tokenizer

Biblioteka boost Tokenizer

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.

Klasa Tokenizer

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:

  • TokenizerFunc - funktor używany do dzielenia sekwencji
  • Iterator - typ iteratora specyfikującego sekwencję
  • Type - typ sekwencji


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 Token Iterator

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:

  • TokenizerFunc - funktor używany do dzielenia sekwencji
  • Iterator - typ iteratora specyfikującego sekwencję
  • Type - typ sekwencji


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

Funktory TokenizerFunction

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:

  • char_separator
  • escaped_list_separator
  • offset_separator


Klasa char_separator

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

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:

  • e - określa znak, który przywraca pierwotne znaczenie znaku następującego po nim
  • c - określa znak używany jako separator
  • q - określa znak oznaczający cytowanie


escaped_list_separator(string_type e, string_type c, string_type q):

Parametry konstruktora:

  • e - znaki z łańcucha określaja znaki, które przywracają pierwotne znaczenie znaku następującego po nim, pusty łańcuch określa brak takiego znaku
  • c - każdy znak z łańcucha określa znak używany jako separator, pusty łańcuch określa brak takiego znaku
  • q - znaki z łańcucha określaja znak oznaczający cytowanie, pusty łańcuch określa brak takiego znaku



Klasa offset_separator

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:

  • begin, end - określają początek i koniec sekwencji przesunięć typu int
  • bwrapoffsets - określa, czy przesunięcia po dojściu do końca ich sekwencji, mają być powtarzane cykilcznie true, czy użyte tylko raz false
  • breturnpartiallast - określa, czy podciąg mający mniej znaków niż wymaga to dane przesunięcie, ma być zachowywany true, czy odrzucany false



Michał Płachta H1ISI

tokenizer.txt · ostatnio zmienione: 2008/04/14 08:45 przez mplacht1