Różnice między wybraną wersją a wersją aktualną.
Both sides previous revision Previous revision Next revision | Previous revision | ||
format [2008/04/15 23:06] piechot |
format [2008/04/16 23:50] piechot |
||
---|---|---|---|
Linia 1: | Linia 1: | ||
====== Biblioteka Boost Format ====== | ====== Biblioteka Boost Format ====== | ||
+ | --- //[[tpiechot@stud.elka.pw.edu.pl|Tomasz Piechota G1ISI]] 2008/04/16 23:44// | ||
+ | |||
Biblioteka Boost Format dostarcza klasę do formatowania argumentów zgodnie z dostarczonym łańcuchem formatującym. Podstawowe różnice w stosunku do funkcji printf, to m.in.: | Biblioteka Boost Format dostarcza klasę do formatowania argumentów zgodnie z dostarczonym łańcuchem formatującym. Podstawowe różnice w stosunku do funkcji printf, to m.in.: | ||
* deterministyczne zachowanie, nawet w przypadku podania błędnych argumentów (generuje wyjątek lub ignoruje błąd, w zależności od ustawień). | * deterministyczne zachowanie, nawet w przypadku podania błędnych argumentów (generuje wyjątek lub ignoruje błąd, w zależności od ustawień). | ||
Linia 58: | Linia 60: | ||
std::cout << frm << std::endl; // --> "% _Foo_ _2_ _Bar_ %" | std::cout << frm << std::endl; // --> "% _Foo_ _2_ _Bar_ %" | ||
</code> | </code> | ||
+ | |||
+ | |||
Linia 78: | Linia 82: | ||
Argumenty ujęte w nawiasy kwadratowe są opcjonalne, a dla typu drugiego (%|spec|) również ''type-char''. | Argumenty ujęte w nawiasy kwadratowe są opcjonalne, a dla typu drugiego (%|spec|) również ''type-char''. | ||
- | Znaczenie poszczególnych parametrów: | + | ==== Znaczenie poszczególnych parametrów ==== |
- | * N - oznacza numer argumentu | + | |
+ | * N - numer argumentu | ||
* flags - jedna lub więcej spośród flag: | * flags - jedna lub więcej spośród flag: | ||
* '-' - wyrównuje wynikowy łańcuch do lewej strony (ma sens przy jednoczesnym użyciu parametru ''width'' | * '-' - wyrównuje wynikowy łańcuch do lewej strony (ma sens przy jednoczesnym użyciu parametru ''width'' | ||
Linia 100: | Linia 105: | ||
* s or S - łańcuch znaków | * s or S - łańcuch znaków | ||
* c or C - jeden znak | * c or C - jeden znak | ||
+ | |||
+ | |||
+ | |||
+ | ==== Przykłady formatowania przy użyciu łańcucha znaków ==== | ||
Przykłady użycia poszczególnych formatowań pokazane są w poniższym kodzie: | Przykłady użycia poszczególnych formatowań pokazane są w poniższym kodzie: | ||
<code cpp> | <code cpp> | ||
- | //TODO | + | // Sposób pierwszy według formatu %spec |
+ | std::cout << boost::format("_%1$d_ _%1$o_ _%1$#o_") % 10 << std::endl; // --> "_10_ _12_ _012_" | ||
+ | std::cout << boost::format("_%1$d_ _%1$x_ _%1$#X_") % 47 << std::endl; // --> "_47_ _2f_ _0X2F_" | ||
+ | std::cout << boost::format("_%1$5.2f_ _%1$=5.0f_ _%1$05.0f_") % 48.237 << std::endl; // --> "_48.24_ _ 48 _ _00048_" | ||
+ | |||
+ | // Sposób drugi według formatu %|spec| | ||
+ | std::cout << boost::format("_%|1$-6|_ _%|2$+-7.2f|_") % "foo" % 23.199 << std::endl; // --> "_foo _ _+23.20 _" | ||
+ | std::cout << boost::format("_%|6.2e|_ _%|11.3e|_") % 30.2312 % 312.3 << std::endl; // --> "_3.02e+001_ _ 3.123e+002_" | ||
+ | |||
+ | // Trzeci sposób według formatu %N% | ||
+ | std::cout << boost::format("%1% %2% %1% %2%") % "o_O" % "O_o" << std::endl; // --> "o_O O_o o_O O_o" | ||
</code> | </code> | ||
W jednym łańcuchu możemy korzystać z różnych sposóbów, natomiast błędem jest użycie zarówno argumentów numerowanych, jak i nienumerowanych. | W jednym łańcuchu możemy korzystać z różnych sposóbów, natomiast błędem jest użycie zarówno argumentów numerowanych, jak i nienumerowanych. | ||
<code cpp> | <code cpp> | ||
- | std::cout << boost::format("%d %s") % 10 % "foo" << std::endl; // OK | + | std::cout << boost::format("%d %|s|") % 10 % "foo" << std::endl; // OK |
- | std::cout << boost::format("%1$s %2$s") % "foo" % "bar" << std::endl; // OK | + | std::cout << boost::format("%1$s %2%") % "foo" % "bar" << std::endl; // OK |
- | std::cout << boost::format("%1$d %s") % 10 % "bar" << std::endl; // BŁĄD! | + | std::cout << boost::format("%1$d %s") % 10 % "bar" << std::endl; // BŁĄD! |
</code> | </code> | ||
+ | Ciekawym przykładem może być również technika wymuszająca wcięcie (z wypełnieniem lub bez) niezależnie od długości poprzednich argumentów: | ||
+ | <code cpp> | ||
+ | // w obu przypadkach liczba 199 zaczyna się po 15 znakach | ||
+ | std::cout << boost::format("%s %|15t|%d%") % "Abcdefgh" % 199 << std::endl; // --> "Abcdefgh 199" | ||
- | ===== Ciekawe przykłady użycia ===== | + | // z wypełnieniem (duże T + wypełniacz) |
+ | std::cout << boost::format("%s %|15T-|%d%") % "Abcde" % 199 << std::endl; // --> "Abcde ---------199" | ||
+ | </code> | ||
+ | |||
+ | ==== Formatowanie poprzez manipulatory - metoda group() ==== | ||
+ | |||
+ | Na wygląd formatowania poszczególnych parametrów możemy wpływać także mając już zdefiniowany łańcuch formatujący (utworzony obiekt klasy boost::format). Tak zdefiniowane formatowanie ma wyższy priorytet od tego wpisanego w konstruktorze. Manipulatory dostępne są po dołączeniu biblioteki ''iomanip''. | ||
+ | |||
+ | <code cpp> | ||
+ | #include <iomanip> | ||
+ | |||
+ | // (...) | ||
+ | |||
+ | // Pierwsze wystapienie argumentu pierwszego również ma szerokość 5 (priorytet manipulatora większy) | ||
+ | std::cout << boost::format("_%1$3d_ _%1%_") % boost::io::group(showpos, std::setw(5), 101); // --> "_ +101_ _ +101_" | ||
+ | |||
+ | // Manipulatory nie resetują wszystkich, tylko nadpisują istniejące flagi | ||
+ | std::cout << boost::format("_%1$-3d_ _%1%_") % boost::io::group(showpos, std::setw(5), 101); // --> "_+101 _ _ +101_" | ||
+ | , setfill('x') | ||
+ | |||
+ | |||
+ | // Inny przykład | ||
+ | std::cout << boost::format("_%1%_") % boost::io::group(hex, std::setw(5), 99); // --> "_ 63_" | ||
+ | std::cout << boost::format("_%|=10|_") % boost::io::group(setfill('-'), 101); // --> "_----101---_" | ||
+ | </code> | ||
+ | |||
+ | Funkcja ''boost::io::group'' może przyjąc wiele manipulatorów, jednak ostatnim argumentem musi być wartość przekazywanego parametru. | ||
+ | |||
+ | |||
+ | ===== Wyjątki i ich konfiguracja ===== | ||
+ | |||
+ | Boost Format wprowadza pewną liczbę zasad korzystania z objektów ''boost::format'': | ||
+ | * Łańcuch znaków musi przestrzegać składni opisanej powyżej | ||
+ | * Użytkownik musi dostarczyć dokładnie taką liczbę argumentów, jakie zadeklarował w łańcuchu, przed pobraniem sformatowanego wyjścia | ||
+ | * Używając metod ''modify_item'' oraz ''bind_arg'', indeksy elementów i argumentów muszą być właściwe | ||
+ | |||
+ | Jeśli klasa format wykryje, że jedna z powyższych zasad nie jest spełniona, odpowiedni wyjątek zostanie rzucony. | ||
+ | Użytkownik jednak ma możliwość wpłynięcia na zachowanie obiektu, deklarując które błędy mają skutkować wyjątkiem, a które mają zostać przemilczane (wyjście zostanie wygenerowane z pustą wartością danego argumentu). | ||
+ | |||
+ | W celu ustawienia ''bitów błędów'' wykorzystuje się metody: | ||
+ | <code cpp> | ||
+ | unsigned char exceptions(unsigned char newexcept); // ustaw i zwróć | ||
+ | unsigned char exceptions() const; // tylko zwróć | ||
+ | </code> | ||
+ | |||
+ | Dostępne są następujące bity błędów: | ||
+ | * boost::io::bad_format_string_bit - reakcja na błędny format łańcucha formatującego | ||
+ | * boost::io::too_few_args_bit - za mało argumentów | ||
+ | * boost::io::too_many_args_bit - za dużo argumentów | ||
+ | * boost::io::out_of_range_bit - nieprawidłowy index dostarczony podczas wywołania np metody ''modify_item'' | ||
+ | * boost::io::all_error_bits - reakcja na wszystkie błędy | ||
+ | * boost::io::no_error_bits - brak reakcji na jakikolwiek błąd | ||
+ | |||
+ | Przykładowy kod prezentujący działane metod exceptions i bitów błędów: | ||
+ | <code cpp> | ||
+ | boost::format f("_%1%_ _%2%_"); | ||
+ | f % 10; | ||
+ | try | ||
+ | { | ||
+ | std::cout << f << std::endl; | ||
+ | } | ||
+ | catch (boost::io::too_few_args &e) | ||
+ | { | ||
+ | std::cout << "Za malo argumentow" << std::endl; | ||
+ | } | ||
+ | f.exceptions(~boost::io::too_few_args_bit); | ||
+ | try | ||
+ | { | ||
+ | std::cout << f << std::endl; | ||
+ | } | ||
+ | catch (boost::io::too_few_args &e) | ||
+ | { | ||
+ | std::cout << e.what() << std::endl; | ||
+ | } | ||
+ | |||
+ | // --> "Za malo argumentow" | ||
+ | // --> "_10_ __" | ||
+ | </code> | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | ===== Przykład użycia ===== | ||
+ | Poniższy program wyświetla listę produktów w postaci sformatowanej tabeli | ||
+ | |||
+ | <code cpp> | ||
+ | #include <iostream> | ||
+ | #include <boost/format.hpp> | ||
+ | #include <string> | ||
+ | #include <list> | ||
+ | |||
+ | using namespace std; | ||
+ | using namespace boost; | ||
+ | |||
+ | class Produkt | ||
+ | { | ||
+ | public: | ||
+ | Produkt(string n, int i, float c, float z) : nazwa(n), ilosc(i), cena(c), zmiana(z) { } | ||
+ | string nazwa; | ||
+ | int ilosc; | ||
+ | float cena; | ||
+ | float zmiana; | ||
+ | }; | ||
+ | |||
+ | int main(int argc, char *argv[]) | ||
+ | { | ||
+ | // Lista obiektów | ||
+ | list<Produkt> p; | ||
+ | p.push_back(Produkt("Widelec", 4, 4.99f, 1.021f)); | ||
+ | p.push_back(Produkt("Łopatka", 32, 2.99f, -10.2292f)); | ||
+ | p.push_back(Produkt("Packa", 19, 19.39f, 19.1133f)); | ||
+ | |||
+ | |||
+ | // pozioma linia | ||
+ | format line("%|55T-|"); | ||
+ | |||
+ | // nazwa: %|1$-.20s| - wyrownanie do lewej, maksimum 20 znakow | ||
+ | // ilość: %2% - bez dodatkowego formatowania | ||
+ | // cena: %|3$.2f| - liczba zmiennoprzecinkowa, do dwóch miejsc po przecinku | ||
+ | // zmiana: %|4$+10.4f| - wymuszenie wyświetlania znaku +, szerokosc 10, do 4 miejsc po przecinku, wyrównanie do prawej | ||
+ | format row("|%|1$-20.20s|%|21t||%2%%|32t||%|3$.2f|%|43t||%|4$+10.4f|%|54t||"); | ||
+ | |||
+ | cout << line << endl; | ||
+ | cout << row % "Nazwa produktu" % "Ilosc" % "Cena" % "Zmiana (%)" << endl; | ||
+ | cout << line << endl; | ||
+ | | ||
+ | for (list<Produkt>::const_iterator it = p.begin(); it != p.end(); it++) | ||
+ | cout << row % it->nazwa % it->ilosc % it->cena % it->zmiana << endl; | ||
+ | | ||
+ | cout << line << endl; | ||
+ | | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | </code> |