Różnice między wybraną wersją a wersją aktualną.
Both sides previous revision Previous revision | Last revision Both sides next revision | ||
regex [2008/04/16 16:01] przemoc wersja preprefinalna |
regex [2008/04/17 00:19] przemoc wersja prefinal |
||
---|---|---|---|
Linia 1: | Linia 1: | ||
====== Wyrażenia regularne oczami programisty C++, czyli Boost.Regex ====== | ====== Wyrażenia regularne oczami programisty C++, czyli Boost.Regex ====== | ||
- | [[przemoc@gmail.com|Przemysław Pawełczyk G1ISI]] | + | __Przemysław Pawełczyk G1ISI__ |
W życiu każdego programisty przychodzi czas, w którym musi poznać wyrażenia regularne (z różnych przyczyn), a znając już je, używa ich chętnie i bez oporów, przynajmniej w skryptach shellowych (a de facto w programach typu [[wp>AWK]], [[wp>grep]] czy [[wp>sed]]) i w interpretowanych językach jak [[wp>PHP]], [[wp>Perl]], [[wp>Ruby_(programming_language)|Ruby]] oraz innych. | W życiu każdego programisty przychodzi czas, w którym musi poznać wyrażenia regularne (z różnych przyczyn), a znając już je, używa ich chętnie i bez oporów, przynajmniej w skryptach shellowych (a de facto w programach typu [[wp>AWK]], [[wp>grep]] czy [[wp>sed]]) i w interpretowanych językach jak [[wp>PHP]], [[wp>Perl]], [[wp>Ruby_(programming_language)|Ruby]] oraz innych. | ||
Linia 107: | Linia 107: | ||
#include <boost/regex.hpp> | #include <boost/regex.hpp> | ||
</code> | </code> | ||
+ | Przy linkowaniu musimy natomiast dołączyć bibliotekę Boost.Regex, co w systemach *nixowych odbywa się za pomocą parametru '-lboost_regex'. | ||
+ | |||
Tak jak w przypadku innych bibliotek Boosta, wszystkie stałe, klasy i funkcje zewnętrzne znajdują się przestrzeni nazw ''boost'' i dla przejrzystości nie będę tego pisał przy przytaczaniu fragmentów definicji podstawowych elementów Boost.Regex. | Tak jak w przypadku innych bibliotek Boosta, wszystkie stałe, klasy i funkcje zewnętrzne znajdują się przestrzeni nazw ''boost'' i dla przejrzystości nie będę tego pisał przy przytaczaniu fragmentów definicji podstawowych elementów Boost.Regex. | ||
Linia 133: | Linia 135: | ||
Najważniejszy jest jednak konstruktor: | Najważniejszy jest jednak konstruktor: | ||
<code cpp> | <code cpp> | ||
- | explicit basic_regex(const charT* p, flag_type f = regex_constants::normal); | + | explicit basic_regex(const charT* p, flag_type f = regex_constants::normal); |
</code> | </code> | ||
który przyjmuje sekwencję znaków zawierającą wyrażenie regularne oraz tryb przetwarzania tego wyrażenia. | który przyjmuje sekwencję znaków zawierającą wyrażenie regularne oraz tryb przetwarzania tego wyrażenia. | ||
W przypadku niepoprawnego wyrażenia regularnego rzucany jest wyjątek ''boost::regex_error'' (dawniej ''boost::bad_expression'' lub ''boost::bad_pattern'', które są teraz aliasami do ''boost::regex_error'' dla wstecznej kompatybilności), chyba że przekazano flagę ''regex_constants::no_except''. | W przypadku niepoprawnego wyrażenia regularnego rzucany jest wyjątek ''boost::regex_error'' (dawniej ''boost::bad_expression'' lub ''boost::bad_pattern'', które są teraz aliasami do ''boost::regex_error'' dla wstecznej kompatybilności), chyba że przekazano flagę ''regex_constants::no_except''. | ||
- | Mamy następujące podstawowe (nieuzależnione od wybranej składni) tryby przetwarzania): | + | Mamy następujące podstawowe (nieuzależnione od wybranej składni) tryby przetwarzania: |
<code cpp> | <code cpp> | ||
namespace regex_constants { | namespace regex_constants { | ||
Linia 184: | Linia 186: | ||
</code> | </code> | ||
- | Dopasowania to tak naprawdę kolekcje poddopasowań ''boost::sub_match'', do których dostęp mamy jedynie poprzez ''operator[]'' klasy ''boost::match_results''. | + | Dopasowania to tak naprawdę kolekcje poddopasowań ''boost::sub_match'', do których dostęp mamy jedynie poprzez ''operator[]'' klasy ''boost::match_results''. Obiekt klasy ''boost::sub_match'' posiada kilka przydatnych składowych: boolowską ''matched'' informującą o tym czy dane znaczone podwyrażenie brało udział w dopasowaniu i jeżeli tak, to iteratory ''first'', ''second'' wskazujące na początek oraz koniec (z wyłączeniem) w ciągu, który pokrył to dopasowanie. |
+ | Mając obiekt tej klasy, nazwijmy go m, odwołania do poszczególnych elementów wyglądają następująco: | ||
+ | ^ Boost.Regex ^ Perl ^ Opis ^ | ||
+ | | m.prefix() | $` | treść poprzedzająca dopasowanie | | ||
+ | | m[0] | $& | cała dopasowana treść | | ||
+ | | m[1] | $1 | pierwsze znaczone podwyrażenie | | ||
+ | | ... || kolejne znaczone podwyrażenia | | ||
+ | | m[n] | $n | n-te znaczone podwyrażenie | | ||
+ | | m.suffix() | $' | treść następująca po dopasowaniu | | ||
+ | |||
+ | Szablon klasy ''match_results'' posiada także metody | ||
+ | <code cpp> | ||
+ | const_iterator begin() const; // Zwraca startowy iterator znaczonych podwyrażeń. | ||
+ | const_iterator end() const; // Zwraca terminujący iterator znaczonych podwyrażeń. | ||
+ | </code> | ||
+ | które ułatwiają realizację wygodnego iterowania po znaczonych podwyrażeniach. | ||
+ | |||
+ | Dostępne są ponadto różne tryby dopasowań, przekazywane w funkcjach niżej omówionych. Przykłady to: | ||
+ | <code cpp> | ||
+ | namespace regex_constants { | ||
+ | typedef implemenation-specific-bitmask-type match_flag_type; | ||
+ | | ||
+ | static const match_flag_type match_default = 0; // Zachowanie domyślne (zgodne z ECMA-262) | ||
+ | /* ... */ | ||
+ | static const match_flag_type match_not_null; // Dopasowanie nie może być puste. | ||
+ | /* ... */ | ||
+ | static const match_flag_type match_single_line; // ^ odpowiada za początek tekstu, | ||
+ | // a $ - koniec tekstu. | ||
+ | /* ... */ | ||
+ | static const match_flag_type format_no_copy; // Sekcje tekstu niepasujące do wyrażenia | ||
+ | // regularnego nie są kopiowane do | ||
+ | // wyjściowego łańcucha znaków. | ||
+ | /* ... */ | ||
+ | static const match_flag_type format_all; // Aktywuje wszystkie dostępne rozszerzenia | ||
+ | // składni, włączając w to warunkowe podstawienia. | ||
+ | } | ||
+ | </code> | ||
===== Możliwości Boost.Regex ===== | ===== Możliwości Boost.Regex ===== | ||
Same szablony klas ''boost::basic_regex'' oraz ''boost::match_results'' byłyby nic nie warte bez funkcji, które na nich operują realizując podstawowe przypadki użycia wyrażen regularnych. | Same szablony klas ''boost::basic_regex'' oraz ''boost::match_results'' byłyby nic nie warte bez funkcji, które na nich operują realizując podstawowe przypadki użycia wyrażen regularnych. | ||
- | Poniżej omówione szablony funkcji parametryzowane są różnymi elementami w zajemności od wersji (pominę dokładne deklaracje tych szablonów), ale zawsze jest to m.in. typ znaku. | + | Poniżej omówione szablony funkcji parametryzowane są różnymi elementami w zależności od wersji (pominę dokładne deklaracje tych szablonów), ale zawsze jest to m.in. typ znaku. |
==== Dopasowywanie (matching) - regex_match ==== | ==== Dopasowywanie (matching) - regex_match ==== | ||
Linia 214: | Linia 252: | ||
const basic_regex<charT, traits>& e, | const basic_regex<charT, traits>& e, | ||
match_flag_type flags = match_default); | match_flag_type flags = match_default); | ||
+ | </code> | ||
+ | |||
+ | Chyba najważniejsze w tej funkcji jest to, że dopasowaniu musi ulec cały tekst, dlatego też asercje użyte na początku i końcu wyrażenia regularnego (^ i $ odpowiednio) nie mają najmniejszego znaczenia (o czym już wcześniej wspomniałem w mikropokazie). | ||
+ | |||
+ | Najczęściej używana jest do badania poprawności przekazanych danych. | ||
+ | |||
+ | <code cpp> | ||
+ | #include <iostream> | ||
+ | #include <string> | ||
+ | #include <boost/regex.hpp> | ||
+ | |||
+ | namespace validations { | ||
+ | // Wyrażenie regularne zgodne z formatem IBAN | ||
+ | // IBAN = International Bank Account Number | ||
+ | static const boost::regex ibanFormat("[A-Z]{2}\\d{2} ?[A-Z\\d]{4}( ?\\d{4}){1,} ?\\d{1,4}"); | ||
+ | |||
+ | // Sprawdź czy string ma format IBAN | ||
+ | bool hasIbanFormat(const std::string& s) | ||
+ | { | ||
+ | return regex_match(s, ibanFormat); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Wczytaj linię z wejścia i sprawdź czy to może być IBAN, | ||
+ | // wówczas zwróć 1, w przeciwnym przypadku - 0. | ||
+ | int main() { | ||
+ | std::string line; | ||
+ | std::getline(std::cin, line); | ||
+ | std::cout << validations::hasIbanFormat(line) << std::endl; | ||
+ | return 0; | ||
+ | } | ||
</code> | </code> | ||
Linia 232: | Linia 301: | ||
match_flag_type flags = match_default); | match_flag_type flags = match_default); | ||
- | // Wesja główna, wołana także przez powyższze | + | // Wesja główna, wołana także przez powyższe |
template <class BidirectionalIterator, class Allocator, class charT, class traits> | template <class BidirectionalIterator, class Allocator, class charT, class traits> | ||
bool regex_search(BidirectionalIterator first, | bool regex_search(BidirectionalIterator first, | ||
Linia 282: | Linia 351: | ||
match_flag_type m = match_default); | match_flag_type m = match_default); | ||
/* ... */ | /* ... */ | ||
- | } | + | }; |
</code> | </code> | ||