Published: Jan, 2015
Language: Polish

 
Informacje zawarte w niniejszej publikacji są udostępniane na zasadzie „As Is” bez jakichkolwiek gwarancji. Autor dołożył wszelkich starań, by informacje zawarte w niniejszej książce pozostawały poprawne, precyzyjne, aktualne i prawidłowe, Autor nie ponosi jednakże żadnego rodzaju odpowiedzialności, ani bezpośredniej, ani pośredniej, za jakiekolwiek szkody wynikłe w rezultacie wykorzystania informacji zawartych w niniejszej książce, bowiem ani nie może przewidzieć, ani nie może mieć wpływu na sposoby ich wykorzystania.
 
Niniejsza książka przeznaczona jest do osobistego użytku i wykorzystania przez Czytelnika i nie może być ponownie sprzedawana, ani oferowana w jakiejkolwiek innej formie osobom trzecim. Każdy Użytkownik proszony jest o uzyskanie własnej, legalnej kopii.
 
 
C. Żadna część niniejszej książki nie może być kopiowana, powielana, ani rozpowszechniana wtórnie za pośrednictwem nośników fizycznych, ani elektronicznych, bez pisemnej zgody Autora, gdyż stanowi to naruszenie Praw Autorskich. Użyte natomiast w książce wyrażenia regularne nie są zastrzeżone i mogą być stosowane w wyszukiwarkach i aplikacjach bez ograniczeń. W razie wykorzystania cytatów, by pozostać w zgodzie z Prawem i Dobrym Obyczajem, należy wskazać jednoznacznie źródło.
 
 
Adam Majczak
 
C++11:
Zrozumieć Wyrażenia Regularne
 
Druga Edycja Polska
(poprawiona i uzupełniona)
 
 
 
C++11: Understanding Regular Expressions
by
Adam Majczak
 
The Second Polish Edition
(updated and improved)
C. Adam Majczak, 2015, All Rights Reserved
 
The Smashwords' Polish Edition
 
 
E-Edition, License Notes
 
This e-book is licensed for your personal use only. This e-book may not be re-sold or given away to others. If you would like to share this book with another person, please purchase an additional copy for each recipient.
 
The information in this book is distributed on an “As Is” basis, without warranty. While every precaution has been taken in the preparation of this book, the publisher and the author assume no responsibility for errors or omissions, or for damages resulting from the use of the information contained herein.
Adam Majczak
 
C++11: Zrozumieć wyrażenia regularne
 
SPIS TREŚCI:
 
 
Dla kogo przeznaczona jest ta książka?
Przedmowa do pierwszego wydania
 
SPIS LISTINGÓW:
 
Część I – Specyfika składni i notacji C++11
 
ROZDZIAŁ 1: Wprowadzenie
 
Kompilatory, konsolidatory, stadia tworzenia kodu wykonywalnego
Dostępne kompilatory C++ i kompilacja online
IDE dla C++11 online
IDE dla C++14 online
Podsumowanie rozdziału
 
ROZDZIAŁ 2: Konstrukcja kodu źródłowego w C++11
 
Koncepcja przestrzeni nazw namespace
Funkcja main()
Komentarze w C++11 – bez zmian
Zmienne numeryczne w C++11 i słowo kluczowe auto
Standardowe typy zmiennych numerycznych, zakresy wartości, aliasy
Stałe, czyli konstanty
Typ porządkowy enum, inne kategorie stałych
Typ porządkowy w C++11 (enum class)
 
ROZDZIAŁ 3: Tablice numeryczne i łańcuchy znaków
 
Rozpowszechniona NIEPRAWDA: nazwa tablicy to nie to samo co wskaźnik
Obsługa łańcuchów znaków w formacie ASCIIZ
Przydatne elementy składni C, <iso646.h>
Tablice dynamiczne po raz pierwszy
Wskaźniki
Wymiar wskaźnika
Wskaźniki do struktur i do pól struktury
Jak zastosowanie typedef pozwala uzyskać zmienny skok wskaźnika
Pusty wskaźnik donikąd, czyli nullptr w C++11
Dynamiczne tablice z zmiennej wielkości tworzone operatorem new
Makroinstrukcja assert()
Jak postępować z dynamicznymi tablicami?
 
ROZDZIAŁ 4: Rozszerzenia C++11, pętla for i funkcja for_each()
 
Identyfikacja typu w C++11: typeid()
Pętla for w C++11
Interesująca funkcja for_each()
Binarna postać danych w C++11
Zastosowanie kontenera std::array
Łańcuch typu string jako kontener
 
Część II: Wyrażenia regularne w C++11
 
ROZDZIAŁ 5: Zrozumieć wyrażenia regularne
 
Bardzo krótka historia wyrażeń regularnych (GREP)
Nowe podejście C++11 do obsługi wyrażeń regularnych
Rozbudowa wzorca z uwzględnieniem znaków opcjonalnych
Budowanie wyrażeń regularnych krok po kroku
Wyrażenia regularne dla danych numerycznych w różnych formatach
Liczby szesnastkowe
Znaki specjalne w wyrażeniach regularnych - metacharacters
 
ROZDZIAŁ 6: Funkcje regex_search() i regex_match()
 
Funkcja regex_match()
Specyfika notacji C++
Wykorzystanie powtarzających się znaków
Grupy i odwołania do grup
Klasy znaków są wygodne w stosowaniu
 
ROZDZIAŁ 7: Więcej o maszynerii z biblioteki <regex>
 
Różne formaty wzorców
Jak zignorować wielkość liter – flaga icase
Pozycja w łańcuchu znaków
 
ROZDZIAŁ 8: Iteratory
 
Pierwszy iterator specjalny - regex_iterator
Przydatne metody prefix() oraz suffix()
 
ROZDZIAŁ 9: Zastępowanie tekstów, funkcja regex_replace()
 
Typowe zastosowania algorytmu regex_replace()
Kolejność automatycznej numeracji grup
Trzy najistotniejsze flagi i tryby działania funkcji
 
ROZDZIAŁ 10: Podział tekstu na tokeny i obsługa wyjątków
 
Klasyczna funkcja strtok() z biblioteki <string.h>
Jak, zamiast funkcji, zastosować iterator?
Jak regex_token_iterator wykorzystuje grupy?
Dopasowania częściowe (sub-match)
Jak regex_token_iterator może zastąpić funkcjonalność regex_replace()?
Tokenem może być zbitka
Jak liczą wyrażenia regularne (sprawdzanie formalnej poprawności dat)
Obsługa wyjątków
 
ROZDZIAŁ 11: Analizujemy kontekst
 
Technika „looking forward”, czyli, co jest po?
Nie szafujmy nawiasami i grupami (zaskakujące efekty uboczne)
Wykrywanie słów i badanie kontekstu
Rozmiar ma (czasem) znaczenie
 
ROZDZIAŁ 12: Przykłady zastosowań wyrażeń regularnych
 
Walidacja adresów email
Walidacja danych na wejściu
Obsługa dat, znaczników XML, nieco szczegółów technicznych
Zastosowanie iteratora i funkcji for_each()
Selekcja negatywna (odrzucamy elementy tekstu)
Nakładamy dodatkowe warunki na hasło użytkownika
Zapamiętujemy lub pomijamy grupy znaków w dopasowaniach
 
ZAKOŃCZENIE
 
Dodatek
 
Lista sygnatur funkcji obsługujących wyrażenia regularne w C++11.
Najprostszy pomiar czasu
 
Dla kogo przeznaczona jest ta książka?
 
Wprowadzenie standardów C++11 i C++14 spowodowało, że obsługa wyrażeń regularnych weszła w skład standardowej biblioteki C++ (C++11 Standard Library). Dostępność biblioteki STL (Standard Template Library) oraz własnej, specjalnej biblioteki do obsługi wyrażeń regularnych <regex> spowodowała, że przetwarzanie wyrażeń regularnych w C++11 i C++14 stało się prostsze. Skoro jednakże zmienił się zestaw dostępnych narzędzi (rozszerzono również zestaw słów kluczowych języka), zmienił się także styl programowania.
 
W porównaniu z wcześniejszymi wersjami (POSIX, PCRE, itp.) nowa biblioteka <regex> C++11 stosuje nowe, w pełni obiektowe podejście do budowy i obsługi wyrażeń regularnych (patrz także podrozdział: Bardzo krótka historia wyrażeń regularnych)Biblioteka <regex> zawiera nowe algorytmy (szablony funkcji) i nowe iteratory. Tworzenie programów wykorzystujących wyrażenia regularne stało się szybsze, wygodniejsze i prostsze, ale metodyka w C++11 jest całkowicie nowa i odmienna.
 
Wydaje się zatem, że niniejszy ebook może okazać się interesującą i przydatną lekturą dla wszystkich, którzy stosują, lub zamierzają stosować nowe wersje kompilatorów języka: C++11 oraz C++14, bez względu na środowisko operacyjne. Choć tworzenie oprogramowania dla środowiska operacyjnego Windows, czy Linux ma, oczywiście, swoja specyfikę, obsługa wyrażeń regularnych w C++11/C++14 nie jest zależna od systemu operacyjnego. Poznanie nowej techniki programowania z wykorzystaniem biblioteki <regex> oraz lepsze zrozumienie działania wyrażeń regularnych może okazać się przydatne dla wszystkich użytkowników C++.
 
Dodatkową, praktyczną, użytkową zaletą niniejszego ebooka jest wygoda i prostota użytkowania. Za pomocą zwykłego [Ctrl\+[C\ i [Ctrl\+[V\ można skopiować każdy z ponad 160 przykładowych programów do kompilatora C++ online i uruchomić przykład dosłownie w kilka sekund bez konieczności instalowania jakiegokolwiek oprogramowania. To po prostu działa od zaraz.
 
 
Niełatwo pisać o C++11 „sienkiewiczowską polszczyzną”
 
Język dziewiętnastowieczny w stylu „Bacz waćpan, azaliż dostrzegasz różnicę pomiędzy algorytmem regex_match() a iteratorem regex_iterator?” byłby tu, oczywiście, nie na miejscu. Nie ma wszakże żadnego racjonalnego powodu do jakże powszechnego językowego niechlujstwa.
 
Nasz (ludzki) język zmienia się, by opisywać nowe zjawiska, których wcześniej nie było, lub których wcześniej nie znaliśmy i nie rozumieliśmy. Podobnie i z tych samych powodów zmieniają się języki programowania. Niniejszy ebook stara się jednakże posługiwać prawidłową polszczyzną, a tam, gdzie nie da się uniknąć branżowego żargonu i „nowomowy” (speak like a geek) zazwyczaj podawane są angielskie pierwowzory. Unikając żenującej nowomowy w stylu „Zajebiście miło cię widzieć, wyluzuj...”, Autor stara się wyjaśniać mechanizmy C++11, odpowiadając na typowe (choć czasem niezadane) pytania:
 
* dlaczego w C++11 kod buduje się inaczej, niż robiliśmy to dotychczas np. w C++98?
* jak (i dlaczego) działają różnorodne wyrażenia regularne i do czego może nam się to przydać?
* jakie narzędzie z nowej biblioteki <regex> C++11 można zastosować i dlaczego to nie wszystko jedno, jakich narzędzi użyjemy?
* gdzie i dlaczego często programiści w C++11 popełniają błędy, choć z pozoru wydaje się, że wszystko powinno działać poprawnie?
 
Przedmowa do drugiego wydania
 
Niniejsza książka zawiera ponad 160 listingów przykładowych programów i składa się z 2 części:
 
Część I – Specyfika składni i notacji C++11
Część II – Wyrażenia regularne w C++11
 
Przykłady zawarte w niniejszej książce zawierają podstawowe techniki pozwalające na budowę złożonych, wysoce selektywnych i elastycznych wyrażeń regularnych. Czytelnik znajdzie wśród przykładów:
 
* realizację funkcji logiocznych AND, OR, NOT wobec wyrażeń składowych
* zagnieżdżanie grup i składowych wyrażeń regularnych
* przykłady rozdzielności I łaczności (wyłączenie poza nawias)
* konkatenację (złożenie) wyrażeń regularnych
* analizę kontekstu (przed i po dopasowaniu)
 
W porównaniu do pierwszego wydania uzupełniono obie Części książki, dodając między innymi pomiar czasu (Dodatek) i zliczanie znaków, słów oraz wierszy. Zwiększyła się liczba przykładowych listingów, choć nie wszystkie zostały objęte numeracją i ujęte w spisie listingów. Wszystkie programy przykładowe zostały przetestowane (ze 100%-owym powodzeniem) na kompilatorze C++11 (w wersji Visual C++) oraz C++14 dostępnym online na portalu ideone.com.
 
Część pierwsza ma charakter wprowadzenia. Takie wprowadzenie wydaje się celowe, by ułatwić Czytelnikowi szybkie i dokładne zrozumienie przykładów zawartych w Części 2. Prawie pod wszystkimi przykładami dodano robocze wydruki, samodzielne uruchomienie przykładów (wszystkie można skompilować i uruchomić online) pozwoli jednakże Czytelnikom na wykonanie samodzielnych prób i eksperymentów.
 
 
Rys. 1. Zalecany kompilator C++11 do uruchamiania przykładowych programów obsługujących wyrażenia regularne (Część II).
 
Poniżej umieszczono listę listingów z przykładowymi kodami C++11/C++14 ilustrujących kolejne omówione zagadnienia. Numer listingu zawiera numer Rozdziału oraz numer kolejny, co powinno ułatwić korzystanie z przykładów. Wszystkie listingi zawierają pełne, działające, gotowe do uruchomienia kody C++.
 
SPIS LISTINGÓW:
 
Listing 1.1a. ”Hello World” niby w C, ale działa w C++11.
Listing 1.1b. Strumień cout zamiast funkcji printf().
Listing 1.2. Odczytujemy parametry środowiska na zdalnym serwerze.
 
Listing 2.3. Namespace po raz pierwszy (kod bez std::).
Listing 2.4. Każdy programista może mieć własną przestrzeń namespace.
Listing 2.5. Klauzuli using namespace wystarczy użyć raz.
Listing 2.6. Przykład komunikatu o błędzie Visual C++.
Listing 2.6b. Zastosowanie wskaźnika do wskaźnika: char** p;
Listing 2.7. Operator sizeof() pozwala sprawdzić ile miejsca zajmuje zmienna w pamięci.
Listing 2.8. Słowo kluczoweauto(automatyczna dedukcja typu).
Listing 2.9. Domyślny typ double, rezultat dodawania.
Listing 2.10. Sprawdzamy wielkość podstawowych typów numerycznych.
Listing 2.11. Liczby ósemkowe i szesnastkowe, wymuszona konwersja typu.
Listing 2.12. Różne zastosowania typu char.
Listing 2.13. Liczby typu signed char i unsigned char.
Listing 2.14. Typ long long oraz long double w 32-bitowym środowisku operacyjnym.
Listing 2.15. Logiczna interpretacja wartości stało- i zmiennoprzecinkowych.
Listing 2.16. Kilka sposobów definiowania stałych numerycznych.
Listing 2.17. Jak zmienić dokładność (precyzję na) wydruku.
Listing 2.18. Zastosowanie metody cout.precision().
Listing 2.19. Jak uzyskać maksymalną dokładność dla typu double.
Listing 2.20. Zastosowanie numeric_limits.
Listing 2.21. Wyrażenie stałowartościowe constexpr.
Listing 2.22. Zastosowanie typu porządkowego enum.
Listing 2.23. Predefiniowane stałe matematyczne z grupy M_.
 
Listing 3.24a. Jak C++11 automatycznie zeruje zawartość tablicy.
Listing 3.24b. Jednowymiarowa statyczna tablica znakowa.
Listing 3.25. Uwzględnienie znaku końca łańcucha (format ASCIIZ).
Listing 3.25b. Dlaczego łańcuch znaków ”ALA” składa się z 4 znaków?
Listing 3.25c. Nazwa tablicy jako stała adresowa.
Listing 3.25d. Rozmieszczenie łańcuchów znaków w pamięci przez kompilator.
Listing 3.25e. Zastosowanie wskaźników zmniejsza obciążenie pamięci.
Listing 3.26. Obsługa łańcuchów znaków w formacie ASCIIZ.
Listing 3.27. Kopiowanie i dodawanie (konkatenacja) łańcuchów znaków jak w języku C.
Listing 3.27b. Kopiowanie i dodawanie łańcuchów znaków typu string (C++11).
Listing 3.28. Zliczanie znaków w łańcuchu przy pomocy funkcji C.
Listing 3.29. C++11: zliczanie znaków w łańcuchu typu string przy pomocy metody length().
Listing 3.30. Zmienna typu string automatycznie dostosuje swoją wielkość.
Listing 3.30a. Obsługa długich łańcuchów znaków.
Listing 3.30b. Zależne (skorelowane) pętle programowe.
Listing 3.30c. Funkcje z biblioteki <ctype.h> rozpoznają kategorie znaków.
Listing 3.30d. Liczymy wiersze, słowa i znaki.
Listing 3.31. Wektor i metoda push_back().
Listing 3.33. Wskaźnik (raw pointer) jako adres zmiennej.
Listing 3.34. Komunikat o błędzie, nie da się pobrać adresu R-wartości.
Listing 3.35. Nieprawidłowa deklaracja wskaźnika (typowy, częsty błąd).
Listing 3.36. Prawidłowa deklaracja wskaźnika.
Listing 3.37. Przestawienie wskaźnika tak, by wskazał inna zmienna.
Listing 3.38. Przestawienie wskaźnika o 1 bajt
Listing 3.39. Przestawienie wskaźnika o 4 bajty.
Listing 3.40. Obsługa wskaźnika - funkcja printf() i strumień cout.
Listing 3.41. Wskaźnik do struktury i do pól struktury.
Listing 3.42. Rozmiar wskaźnika.
Listing 3.42b. Wykrywanie niezainicjowanych wskaźników – nullptr.
Listing 3.42c. Operator kropki i pola struktury.
Listing 3.42d. Pola struktury wskazywane przez pointer. Operator [→\.
Listing 3.42e. Dynamiczna tablica tworzona w ruchu programu, operator new.
Listing 3.43. Numeryczna tablica statyczna zgodna z konwencją C.
Listing 3.44. Odwołanie do elementów tablicy przy pomocy wskaźnika.
Listing 3.45. Błędne odwołanie do nieistniejących elementów tablicy.
Listing 3.46. Błędne odwołanie do tablicy poprzez wskaźnik.
Listing 3.47. Odwołanie do elementów dynamicznej tablicy o zmiennej wielkości.
Listing 3.48.Tworzymy tablicę o zadanej wielkości w ruchu programu (operator new).
 
Listing 4.49. Wyznaczamy rozmiar tablicy dla pętli for w ruchu programu.
Listing 4.50. Identyfikacja typu w ruchu programu, C++11: typeid().
Listing 4.51. Identyfikacja typu danych użytkownika w ruchu programu.
Listing 4.51a. Co robi C++11, jeśli zastosujemy słowo auto?
Listing 4.51b. C++11 automatycznie dobiera odpowiedni typ wskaźnika.
Listing 4.52. Inicjujemy tablicę w nagłówku sterującym pętli for.
Listing 4.53. C++11 liczy automatycznie powtórzenia pętli for.
Listing 4.54. Automatyczna adaptacja inteligentnej pętli orogramowej.
Listing 4.54a. Magiczna sztuczka C++11: automatyczna referencja auto&.
Listing 4.55.Funkcja for_each().
Listing 4.56. Zamiana liczby na postać binarną przy pomocy funkcji.
Listing 4.57. Zamiana liczby na postać binarną przy pomocy klasy.
Listing 4.58. Konwersja na postać dwójkową z wykorzystaniem STL (<bitset>).
Listing 4.59. Tablice statyczne typu array<int, n> oraz array<string, k>.
Listing 4.60. Dwubajtowe i czterobajtowe kodowanie znaków w C++11.
Listing 4.60a. Łańcuch typu string obsługiwany jako tablica i jako kontener.
 
Listing 5.61. Pierwsze wyrażenie regularne szuka w tekście łańcucha znaków ”kot”.
Listing 5.62. Dopasowanie do wzorca i funkcja regex_search().
Listing 5.63. Klasyczna składnia języka C (PCRE, kompilator GNU GCC).
Listing 5.64. Wyrażenie regularne: regex r("(kot)(ek)?");
Listing 5.65. Wyrażenie regularne: regex r("....(ko)(t)?(cisko)?(ek)?.");
Listing 5.65a. Wyrażenie [a-d\*.
Listing 5.66. Demonstracja działania wyrażeniaregex r("[b-z\+\\d{3}");
Listing 5.66. Jak realizować funkcję sumy logicznej (OR) w wyrażeniach regularnych.
Listing 5.67. Określamy długość łańcucha znakowego w dopasowaniu.
Listing 5.68. Wyrażenie regex r("[a-z\+\\s[a-z\\\s\\W\\s\\d+\\W");
Listing 5.69. Wykluczamy znaki niepożądane.
Listing 5.70. Wyrażenie ”((...4)|(.9..)|(..8.)).+)”.
Listing 5.70b. Porównanie działania znaków [?\ oraz [*\.
Listing 5.71. Wyrażenie my_regex = ”^-?\d+(\\.\\d+)?((e|E)-?\\d+)?$”;
Listing 5.71. Kod PHP wychwytujący liczby szesnastkowe:
$my_regex = '/(0x)?#?[A-Fa-f0-9\+/';
Listing 5.72. Działanie wyrażenia my_regex = “^(0x)?#?([A-Fa-f0-9\\\s?)+$”;
Listing 5.73. Działanie znaków [^\ oraz [$\.
Listing 5.73b. Działanie znaków [\\b\.
Listing 5.74. Działanie wyrażeń regex r1("l+o\\b"), r2("\\s.+o.+[^!\");
 
Listing 6.75. Działanie wyrażenia reg1("[[:digit:\\+");
Listing 6.76. Porównanie działania funkcji regex_search() oraz regex_mach().
Listing 6.77. Działanie wyrażenia ”(\\+|-)?[[:digit:\\+(\\.)?[[:digit:\\*”.
Listing 6.78. Działanie wyrażenia regex r("\\++");.
Listing 6.79. Działanie wyrażenia wzorzec = "\\\\";,
Listing 6.79b. Wyrażenie: regex r("\.{1}[+\*/.-\+");
Listing 6.80. Znaki Unicode, wyrażenie: wzorzec = "\\u0050";.
Listing 6.81. Działanie wyrażenia: "\\b(k|s)[a-zA-Z\*t\\b".
Listing 6.81b. Zastosowanie wyrażenia: wzorzec = "(a|b|c)\\1";.
Listing 6.82. Podwójne wsteczne odwołanie do grupy (backreference):
wzorzec = "([a-c\)X\\1Y\\1";.
Listing 6.83. Zastosowanie wyrażenia: r("(A\\d{2})|(\\b\\d{3})");.
Listing 6.84. Zastosowanie tablicy wzorców:
{"[abc\{2}","(a|b|c){2}","(a|b|c)\\1"};.
Listing 6.85. Wykrywanie powtarzających się słów: wzorzec = "([a-zA-Z\+)\\s\\1";
Listing 6.86. Działanie wyrażenia: wzorzec = "\\b(\\w)?(\\w)\\w?\\2\\1";.
Listing 6.87. Wyrażenie: r("^((0x)|#)?([[:xdigit:\\\\s?)+$");
 
Listing 7.88. Działanie wyrażenia: "\\b(\\w)?(\\w)\\w?\\2\\1";
Listing 7.89. Działanie wyrażenia: ”([A-Za-z\+) \\1” == "(\\w+)\\s\\1";.
Listing 7.90. Działanie wyrażenia: wzorzec = "(\\w+)\\s?\\1";.
Listing 7.91. Wystarczy, jeśli funkcja regex_search() znajdzie pierwsze dopasowanie.
Listing 7.92. Określamy pozycję w przeszukiwanym łańcuchu znaków. Obiekt smatch.
Listing 7.93. Określamy pozycję w przeszukiwanym łańcuchu znaków ASCIIZ.
Listing 7.94. Działanie wyrażenia: wzorzec = "\\b(\\w)?(\\w)(\\w)?\\2\\1";.
 
Listing 8.95. Działanie iteratora (dwa iteratory).
Listing 8.95b. Działanie iteratora (pojedynczy iterator).
Listing 8.95c. Przy pomocy iteratora wyodrębniamy słowa i zbitki (liczba + słowo).
Listing 8.96. Działanie iteratora i wyrażenia: "\\b(\\w)?(\\w)\\w?\\2\\1";.
Listing 8.97. Działanie iteratora i wyrażenia: R ("\\b([a|A\l)([^ \*)");
Listing 8.98. Zastosowanie metody suffix().
Listing 8.98b. Zastosowanie funkcji for_each().
Listing 8.98c. Niezamierzone pominięcie pierwszego dopasowania.
Listing 9.99. Zastępowanie – funkcjaregex_replace().
Listing 9.99b. Zastępowanie tylko pierwszego dopasowania (reszta bez zmian).
Listing 9.100. Działanie wyrażenia: string replace = "$1";.
Listing 9.101. Działanie wyrażeń:
wzorzec = "(\\w+)\\s[i\\\s(\\w+)"; replace = "$2 i $1";.
Listing 9.102. Zastępowanie wybranych znaków w słowach, wyrażenie: "a|e|i|o|u|y".
Listing 9.103. Wyszukiwanie i zastępowanie przy pomocy wzorców: [B+\, [$`\, [$'\.
Listing 9.103b. Numeracja grup.
Listing 9.103c. Grupy.
Listing 9.103d . Działanie wyrażenia regex r("<h1>(.+)</h1><p>(.+)</p>");.
 
Listing 10.104. Podział na tokeny, funkcja strtok().
Listing 10.105. Zastosowanie regex_token_iterator z separatorem "[-\\s,\\.\+";.
Listing 10.106. Podział na słowa przy pomocy iteratora.
Listing 10.107. Zastosowanie wzorca: wzorzec = "\\b(pod)([^\\s\*)";
Listing 10.108. Wykorzystujemy podział na grupy: \\1: (pod) oraz \\2: ([^\\s\*)
Listing 10.109. Dopasowania częściowe.
Listing 10.110. Wychwytywanie separatorów (split).
Listing 10.111. Podział na tokeny przy pomocy funkcjiregex_search().
Listing 10.112. Zastosowanie wzorca:"(\\w+)?(\\.)?(\\w+)".
Listing 10.112b. Iterator zastępuje regex_replace().
Listing 10.112c. Wykorzystanie iteratora do zliczania zbitek słownych – R("\\d+\\s[a-zA-Z\+").
Listing 10.112d. Poprawne wyrażenie i błędny wydruk: regex r("\\d{4}/(0?[1-9\|1[0-2\)/(0?[1-9\|[1-2\[0-9\|3[0-1\)");
Listing 10.112e . Po zamianie funkcji to samo wyrażenie działa poprawnie.
Listing 10.112f . Uwaga na numerację grup w iteratorze.
Listing 10.112g. Niestety, regex_token_iterator działa tak, jak algorytm regex_search().
Listing 10.113. Typowa obsługa wyjątków w C++11.
Listing 10.114. Schemat obsługi wyjątków dla wyrażeń regularnych C++11.
Listing 10.115. Obsługa wyjątków w działaniu.
Listing 10.116. Reakcja Visual C++ na błąd formalny w wyrażeniu regularnym.
 
Listing 11.117. Działanie wyrażenia:"\\d+[,\\.\?(\\d)*((?=\\sdol)|(?=\\seur))".
Listing 11.118. Działanie wyrażenia: R ("(\\w+)[,\\\s");.
Listing 11.119. Działanie wyrażenia: R ("(\\w+)[,\\\s\\1");.
Listing 11.120. Działanie wyrażenia: R ("(\\b\\w+)(?=\\s(\\w+\\s)+\\1)");.
Listing 11.121. Zastosowanie metody swap().
Listing 11.122. Zastosowanie metody compare().
Listing 11.123. Zastosowanie wyrażenia w = "^(?!.*vat).*";.
Listing 11.124. Działanie wyrażenia:
w = "^([^V\|V[^A\|VA[^T\)*$"; (odpowiednik: ”^(?:[^V\|f(?!AT))*$).
Listing 11.125. Zastosowanie metody size() do zliczania znaków.
Listing 11.126. Zastosowanie metody size() do automatyzacji pętli programowej.
Listing 11.127. Metoda empty() oraz wyrażenia: R( "([abc\*)[1234\" );.
 
Listing 12.128. Walidacja adresów email:
R( "(\\w+)(.*)(\\w*)@(\\w+)(\\.(\\w+))+", icase );
alternatywnie:
r = "\\b([A-Z0-9\\._%+-\+)(.*)(\\w*)@(\\w+)(\\.(\\w+))+$";
Listing 12.129. Jednoczesne wykorzystanie obiektów typu cmatch oraz smatch.
Wyrażenie: R ("(sub)(.*)");
Listing 12.130. Walidacja na wejściu: R("(\\+|-)?\\d+");
Listing 12.131. Wyrażenia:r1("\\w{10,15}"), r2("\\w*\\d+\\w*\\d+\\w*");.
Listing 12.132. Wyrażenia:
r1("\\w{10,15}"), r2("\\w*\\d+\\w*\\d+\\w*"), r3("\\w*[A-Z\\\w*");
Listing 12.133. Wyrażenia: r1("\\w{10,15}"), r2("\\d(?=\\d)"), r3("[A-Z\");.
Listing 12.134. Wyrażenie: r1("([0-9\{4})-([0-9\{1,2})-([0-9\{1,2})");
Listing 12.135. Wyrażenie: "<(.*)>(.*)</(\\1)>".
Listing 12.136. Wyrażenie: "<(.+)>(.*)</(\\1)>" (XML).
Listing 12.137. Wyrażenia: "(\\w+)\\s[i\\\s(\\w+)"; oraz "$2 oraz $1; ";.
Listing 12.137. Wyrażenie:"<(.+)>(.*)</(\\1)>" (HTML).
Listing 12.138. Wyrażenie: "<.+>[\n\?<(.+)>(.*)</(\\1)>" (HTML).
Listing 12.139. Usuwanie niepożądanych znaków: "\\b[[:alpha:\\+\\d\\,?" .
Listing 12.139b. Filtrowanie hipertekstu.
Listing 12.140. Wyrażenie:
"((?=.*\\d)(?=.*[a-z\)(?=.*[A-Z\)(?=.*[@#_$%\).{6,20})";.
Listing 12.141. Przy formatowaniu metodą format() stosujemy takie same wzorce, jak przy zamianie regex_replace().
Listing 12.142. Zliczanie słów i znaków. Wyrażenia: <.+>, (\\S+), (\\w{7,}).
Listing 12.143. Dopasowania grup smatch M[n\(sub-match).
Listing 12.144. Działanie wyrażeniaR("(T.*)\\s(?:T.*)\\s(H.*)\\s(?:W.*)");.
 
Część I – Specyfika składni i notacji C++11
 
 
ROZDZIAŁ 1: Wprowadzenie
 
Sposób przetwarzania informacji ma znaczenie. Gdyby nie polscy matematycy, którzy rozpracowali niemiecką maszynę szyfrująca Enigma, nie tylko historia II wojny światowej, ale i cała historia świata potoczyłaby się z pewnością zupełnie inaczej.
 
Lapidarne stwierdzenie, że nowoczesna informatyka zaczęła się w 1969 roku, gdy wymyślono język C, jest pewnym uproszczeniem. Było jednakże na tej drodze kilka znaczących, milowych kroków. W 1978 roku Brian Kernighan i Dennis Ritchie opublikowali „Biblię Programistów” (The C programming language, wydaną po polsku jako ”Język ANSI C”). Panowie K&R opisywali w swojej książce tzw. klasyczny styl programowania w języku C, nazywany od ich inicjałów „The K&R style”. Instytut ANSI wziął się za C nieco później i pojawiły się kolejne standardy języka:
 
1989 – ANSI X3.159-1989 – nazywany w skrócie ANSI C (lub C89)
1990 – ISO/IEC 9899:1990 - nazywany w skrócie C90
1999 - ISO/IEC 9899:1999 - nazywany w skrócie C99
2007 – C1X, a następnie: ISO/IEC 9899:2011 - nazywany w skrócie C11
 
Podobnie język C++, który pojawił się jako rozszerzenie C, podlegał rozwojowi, rozszerzeniom i kolejnym standardom.
 
1998 - ISO/IEC 14882:1998 – nazywany w skrócie C++98
2003 - ISO/IEC 14882:2003 – nazywany w skrócie C++03
2011 - ISO/IEC 14882:2011 – nazywany w skrócie C++11
sierpień 2014 - ISO/IEC 14882:2014 - nazywany w skrócie C++14
 
Zwróćmy tu uwagę, że C11 i C++11 to dwa odrębne i różne standardy (ich mylenie prowadzi do błędów i nieporozumień).
 
Wbrew początkowym ambitnym założeniom (a tych najistotniejszych było 3):
 
1. Kolejne wersje C++ będą w pełni kompatybilne z C i z poprzednimi wersjami C++,
2. C (a później C++) stanie się „Lingua Franca”, czyli językiem uniwersalnym, w pełni przenośnym pomiędzy różnymi komputerami i różnymi środowiskami operacyjnymi,
3. Kody źródłowe C/C++ będą poprawnie kompilowane przez wszystkie kompilatory spełniające wymagania standardów C/C++,
 
ciągle nie jest tak do końca. Niniejsza książka nie koncentruje się na specyfice żadnego konkretnego kompilatora C++, dotyczy natomiast konstrukcji samego języka oraz obsługi wyrażeń regularnych w wersji C++11 i C++14. Książka rozpoczyna się od wyjaśnienia (Część I) najistotniejszych (przede wszystkim z punktu widzenia obsługi wyrażeń regularnych) zmian wprowadzonych do C++ wraz ze standardem C++11, by ułatwić Czytelnikom zrozumienie notacji i dalszych przykładów. Kolejne rozdziały (Część II) poświęcone są już meritum zagadnienia, czyli różnym aspektom konstruowania i obsługi wyrażeń regularnych w C++11 / C++14.
 
Do kompilacji przykładowych programów przy przygotowaniu książki wykorzystano dostępne online kompilatory
 
Część II: Visual C++:
(http://webcompiler.cloudapp.net/)
Część I: GNU GCC v. 4.8.3:
(http://www.compileonline.com/compile_cpp11_online.php).
 
Kompilator GCC wykorzystano w pierwszej części książki, natomiast wszystkie przykłady dotyczące wyrażeń regularnych w Części II były kompilowane przez VC++ v. 19.00.22318(x86), Nov. 18, 2014.
Przykładowe kody z tej książki powinny również poprawnie uruchamiać się na dostępnym online kompilatorze C++14:
 
http://ideone.com
(na stronicach: C++ 4.9.2 lub C++14)
 
 
Kompilatory, konsolidatory, stadia tworzenia kodu wykonywalnego
 
Programiści, przy pomocy dowolnych „czystych” edytorów tekstowych (w Windows to np. Notatnik / Notepad, w systemach Linuksowych, powiedzmy Vi, Emacs, itp.), mogą tworzyć pliki tekstowe zawierające kody źródłowe w językach C i C++. Kody źródłowe można tworzyć również w zintegrowanych środowiskach programistycznych (IDE = Integrated Development Environment). W C/C++ można tworzyć projekty (ang. poroject-s) składające się w wielu plików źródłowych. W uproszczeniu, w typowej sytuacji, kolejność przetwarzania plików źródłowych jest następująca:
 
1. Preprocesor przetwarza plik źródłowy (source code) na plik tekstowy gotowy do kompilacji.
2. Kompilator przetwarza plik tekstowy na plik w języku maszynowym (object file).
2.a Przy zastosowaniu opcji Compile via Assembly może zostać wygenerowany plik ASM (asemblera). Wtedy to odrębny asembler tworzy plik OBJ.
3. Konsolidator (linker) dołącza biblioteki (LIB-raries) i generuje plik wykonywalny (w Windows EXE).
 
To bardzo uproszczony schemat, ponieważ dla różnych środowisk operacyjnych mogą dochodzić kompilatory zasobów i linkowanie zasobów (ang. resource compiler, resource linking), nie dotyczy to jednak samego języka C++11, więc tu jedynie wspominam, że istnieje taki obszar zagadnień i spotkamy się z nimi, gdy zechcemy dostosować nasze aplikacje do określonego środowiska operacyjnego.
 
 
Dostępne kompilatory C++ i kompilacja online
 
Wiele kompilatorów i wiele środowisk programistycznych jest dostępne bezpłatnie. Podaję tu kilka przydatnych adresów w sieci www, decyzja i wybór należy jednakże do Czytelnika, a zależy od platformy systemowej (własnego i docelowego środowiska operacyjnego), preferencji uczelni, czy firmy.
 
http://www.visualstudio.com/pl-pl/products/visual-studio-express-vs
http://gcc.gnu.org/
http://www.embarcadero.com.pl/produkty/cbuilder/
https://apps.ubuntu.com/cat/applications/raring/g++/
http://www.codeblocks.org
 
Przystępując do lektury niniejszego podręcznika nie zapominajmy, że język nie jest celem samym w sobie. Jest jedynie narzędziem. „Być, albo nie być” wcale nie brzmi mniej frapująco, niż „To be or not to be”. Bowiem nie to jest najważniejsze, jakim językiem się posługujemy. Najważniejsze jest to, co mamy do powiedzenia (z Mądrości Mojego Dziadka). Czemu zatem służy rozbudowa i unowocześnianie języka C i C++? Chodzi o to, by różne algorytmy numeryczne zapisywać szybciej, wygodniej i tak, by generowany przez kompilator kod maszynowy był coraz bardziej efektywny.
 
Równie wiele jest kompilatorów C++ dostępnych online. Wymienię kilka. Polecam uruchamianie przykładów i wykonywanie własnych ćwiczeń ze wspomnianym powyżej Visual C++, Czytelnik zechce jednakże samodzielnie wybrać najwygodniejszy w stosowaniu.
 
http://www.compileonline.com/compile_cpp11_online.php
https://ideone.com/
http://codepad.org/
https://isocpp.org/blog/2013/01/online-c-compilers
http://webcompiler.cloudapp.net/
 
Posługiwanie się kompilatorem online ma istotne zalety:
 
1. Nie musimy „obciążać” własnego komputera, ani zmieniać jego konfiguracji.
2. Z kompilatorów C++ online możemy korzystać z dowolnego komputera, nawet wtedy, gdy nie mamy uprawnień administratora (do instalowania własnego oprogramowania na lokalnym dysku).
 
Najsłynniejszy chyba program świata, napisany pierwotnie w C, będzie poprawnie kompilowany i poprawnie wykonany w C++11.
 
Listing 1.1a. ”Hello World” niby w C, ale działa w C++11.
 
#include <stdio.h>
int main()
{
printf("Hello World! \n");
}
// wydruk: Hello World!
 
By było jasne, czym różni się C++11, pokażę najpierw – od czego. Zmodyfikuję nieco powyższy kod, zamiast funkcji bibliotecznej C printf(), posłużę się obiektem cout.
 
Listing 1.1b. Strumień cout zamiast funkcji printf().
 
#include <iostream>
int main()
{
std::cout << "Hello World!" << std::endl;
}
// wydruk: Hello World!
 
Zwróćmy uwagę na zmianę w pisowni nazw plików nagłówkowych. W nowej notacji C++ znikają rozszerzenia *.h oraz *.hpp, natomiast w nazwach plików nagłówkowych C pojawia się dodatkowa pierwsza litera „c”. Zmiany nazw są następujące:
 
<iostream.h> → <iostream>
<stdio.h> → <cstdio>
<stdlib.h> → <cstdlib>
...itp.
 
 
Rys. 1.1. Kompilacja i uruchamianie kodów online.
 
Zwróćmy uwagę, że w przypadku kompilatorów online parametry środowiska operacyjnego dotyczą systemu operacyjnego zdalnego serwera (a nie komputera użytkownika). W przypadku GCC będzie to Linux (jak na Rys. 1.1), w przypadku Visual C++ wykorzystywanego w Części II będzie to MS Windows.
 
UWAGA TECHNICZNA:
 
W trakcie pracy nad tekstem tej książki portal www.compileonline.com został przebudowany. Poniżej, na Rysunku 1.1b nowsza wersja (grudzień 2014).
 
 
Rys. 1.1b. Nowsza wersja kompilatora C++11 online.
 
Funkcja biblioteczna C getenv() ma jedną istotną wadę. Jeśli chcemy, by funkcja podała nam stan zmiennej środowiskowej (ang. environment variable settings), musimy wiedzieć, o jaką zmienną nam chodzi i podać jej dokładną nazwę. Jeśli nie jesteśmy pewni, przy pomocy prostego kodu C możemy odczytać wszystkie zmienne środowiskowe.
 
Listing 1.2. Odczytujemy parametry środowiska na zdalnym serwerze.
 
#include <stdio.h>
#include <stdlib.h>
 
main( int argc , char *argv[\ , char *env[\ )
{
int i = 0;
printf( "Parametry srodowiska operacyjnego: \n" );
do
{
printf("%s \n", env[i\);
i++;
} while (env[i\ != NULL);
printf( "Nazwa pliku programu: \n" );
printf( "%s" , argv[0\ );
return 0;
}
// wydruk: zależy od zastosowanego kompilatora i od środowiska operacyjnego
 
Na powyższym rysunku zwróćmy uwagę, że na ekranie widać, która wersja kompilatora i z jakimi parametrami jest stosowana przy kompilacji naszych programów. Możemy uruchamiać program z parametrami (Command Line Arguments) i wczytywać dane w ruchu programu (STDIN Input).
 
 
IDE dla C++11 online
 
Postawmy sobie przykładowe, proste zadanie. Znana anegdotka głosi, że obliczenie sumy liczb naturalnych od 1 do 100 było pierwszym zadaniem, przy którym ujawnił się geniusz matematyczny kilkuletniego wtedy Gaussa. Gauss szybko zauważył, że suma każdej z par liczb:
 
100 + 1 = 101
99 + 2 = 101
98 + 3 = 101
51 + 50 = 101
 
Wystarczyło teraz policzyć ile jest takich par. Po chwili zastanowienia łatwo obliczyć, że po podzieleniu 100 liczb na pary mamy dokładnie 50 par. Jeśli par jest 50, a każda z nich daje w sumie 101, to suma wszystkich liczb wynosi 50 * 101 = 5050. Znamy już zatem końcowy wynik. Teraz przez chwilę nie myślmy tak szybko, jak geniusz Gauss, mamy przecież komputery, które mogą liczyć „mechanicznie” i całkowicie bezmyślnie, czyli tak:
 
suma = 1 + 2 + 3 + … + 98 + 99 + 100;
 
Nie chce nam się tyle pisać, prawda? Więc może nie aż tak bezmyślnie. W klasycznym C możemy to zapisać np. tak:
 
 
Rys. 1.2. Pętla programowa, C++11.
 
Na powyższym rysunku widać, jak pojawiła się opcja ”std=C++11”, mimo to, archaiczny kod jest poprawnie kompilowany i wykonywany. Może zatem z tą kompatybilnością wsteczną nie jest aż tak źle? Przecież to taki styl programowania, który już w latach 70-tych ubiegłego wieku (już na etapie „K&R Style”) był uważany za nieelegancki. Prowokacja intelektualna jest tu zamierzona. Skoki bezwarunkowe (goto) i warunkowe (if-goto) to technika, która od zarania dziejów C i C++ uważana była za już archaiczną i zdecydowanie nieelegancką, mimo to C++11 nadal ją akceptuje. Co prawda w C skok goto może następować w dowolne miejsce kodu, w C++ już nie. Jest pewne ograniczenie. C++ nie pozwoli skoczyć do wnętrza bloku instrukcji (blok instrukcji ujmuje się w nawiasy klamrowe {}). Dla przykładu, taki skok w C++11 jest niedozwolony:
 
// UWAGA: w starszych wersjach OK, ale w C++11 to błąd!
 
goto Etykieta;
{
// blok instrukcji
Etykieta:
// reszta instrukcji bloku
}
 
Jeśli etykieta jest wewnątrz (lub na zewnątrz) bloku instrukcji, taki skok jest w C++11 niedozwolony.
 
Zapiszmy to teraz zgodnie z zasadami programowania strukturalnego. Zamiast instrukcji skoku goto zastosujmy pętlę programową while (wykonuj-dopóki). Dodatkowo zmienimy plik nagłówkowy i zastąpimy funkcję biblioteczną C obiektem C++. Skrócimy również zapis inkrementacji.
 
zapis i = i + 1; zastąpimy przez i++;
 
Po tych kilku zmianach nasz kod C++11 wygląda i działa tak, jak pokazano na rysunku poniżej.
 
 
Rys. 1.3. Ta sama pętla programowa, ale bardziej elegancko.
 
Zwróćmy uwagę, po pierwsze, że C++11 automatycznie zeruje zmienne globalne (to te zadeklarowane na zewnątrz funkcji main()). Po drugie, w nagłówku sterującym pętli programowej typu while możemy modyfikować zmienną sterującą pętli (podobnie jak robimy to w nagłówku pętli for).
 
#include <iostream>
using std::cout;
int i; // globalna zmienna jest zerowana
int main()
{
while ( i++ < 5 ) cout << i << ' ';
}
// wydruk: 1 2 3 4 5
 
 
IDE dla C++14 online
 
Wdrażanie standardu C++11 i C++14 przebiega stopniowo. Stopniowo również modernizowane są kompilatory różnych producentów i kompilatory dostępne online. W chwili zakończenia Drugiej Edycji kompilator C++14 był już dostępny online na portalu IDEONE.COM. Przykłady z Części I i z Części II poprawnie działają na tym kompilatorze (GCC, wersja 4.9.2).
 
 
Podsumowanie rozdziału
 
Standard C++11 został przyjęty przez ISO i uznany przez producentów kompilatorów języka C++. Kompilatory C++11 są dostępne dla popularnych środowisk operacyjnych (Windows, Linux, itd.), w tym niektóre wersje (np. Visual C++ Express Edition) są dostępne bezpłatnie i / lub online. C++11 jest w znacznym stopniu wstecznie kompatybilny z wcześniejszymi wersjami C i C++, jednakże kompilatory różnych producentów i dla różnych środowisk operacyjnych zachowują pewną specyfikę. Obsługa wyrażeń regularnych długo pozostawała nieobjęta standardem i w różnych wersjach C/C++ z różnymi bibliotekami była obsługiwana różnie. Standard C++11 ujednolicił obsługę wyrażeń regularnych w C++, a biblioteka <regex> stała się częścią standardowej biblioteki C++ (C++11 Standard Library).
 
Niniejsza książka koncentruje się na wykorzystaniu do nauki dostępnych online kompilatorów
C++11 – gcc (Linux) i vc++ (Windows). Obydwa te kompilatory są również dostępne bezpłatnie i mogą być, zgodnie z wyborem i decyzją użytkownika, zainstalowane na własnym komputerze.
 
 
Dodatek
 
Lista sygnatur funkcji obsługujących wyrażenia regularne w C++11.
 
Biblioteka <regex> C++11 posługuje się zaledwie trzema algorytmami / szablonami funkcji (ang. function template), tym niemniej, można te funkcje stosować na wiele różnych sposobów.
 
bool regex_match( str, regex )
 
bool regex_match( str, regex, flags )
 
bool regex_match( beg, end, regex )
 
bool regex_match( beg, end, regex, flags )
 
bool regex_match( str, match, regex )
 
bool regex_match( str, match, regex, flags )
 
bool regex_match( beg, end, match, regex )
 
bool regex_match( beg, end, match, regex, flags )
 
bool regex_search( str, regex )
 
bool regex_search( str, regex, flags )
 
bool regex_search( beg, end, regex )
 
bool regex_search( beg, end, regex, flags)
 
bool regex_search( str, match, regex )
 
bool regex_search( str, match, regex, flags )
 
bool regex_search( beg, end, match, regex )
 
bool regex_search( beg, end, match, regex, flags )
 
strRes regex_replace( str, regex, replace )
 
strRes regex_replace( str, regex, replace, flags )
 
outPos regex_replace( outPos, beg, end, regex, replace )
 
outPos regex_replace( outPos, beg, end, regex, replace, flags)
 
gdzie:
 
regex – wyrażenie regularne, wzorzec (pattern)
str – badany łańcuch znaków
beg – początek iteracji
end – koniec iteracji
flags – flagi (przełączniki)
match – rezultat poszukiwania i dopasowania
replace – wzorzec zastępowania (zamiany)
strRes – łańcuch znaków po zamianie
outPos – pozycja
 
 
Najprostszy pomiar czasu
 
Podczas stosowania wyrażeń regularnych (interpretowanych i wykonywanych w ruchu programu) musimy liczyć się z ich czasochłonnością. Wykonajmy dla przykładu prosty pomiar czasu wykorzystania CPU przy pomocy funkcji i struktur C:
 
#include <stdio.h>
#include <time.h>
clock_t ticks;
long count;
int main()
{
for (count = 0; count <= 30000000; ++count)
{
if (count % 10000000 != 0) continue; /* tylko pelne miliony */
ticks = clock();
printf("Performed %ld million integer divisions; \n"
"used %0.4f seconds of CPU time.\n", count / 1000000,
(double)ticks/CLOCKS_PER_SEC);
}
}
// wydruk:
Performed 0 milion integer divisions;
used 0.0021 seconds of CPU time
Performed 10 milion integer divisions;
used 0.0507 seconds of CPU time
Performed 20 milion integer divisions;
used 0.0992 seconds of CPU time
Performed 30 milion integer divisions;
used 0.1477 seconds of CPU time
czyli:
Wykonalem 10 milionow dzielen calkowitych
wykorzystalem 0.0507 sekundy czasu procesora
 
Jak widać z powyższego przykładu, miliony dzieleń całkowitych wykonują się w ułamkach sekund. Oprócz „tykania zegara”:
 
clock_t ticks;
 
i dalej przeliczania go na sekundy przy pomocy predefiniowanej stałej:
 
double sekundy = (double)ticks/CLOCKS_PER_SEC;
 
możemy posłużyć się przy pomiarach czasu strukturami typu time_t.
 
#include <stdio.h>
#include <time.h>
int main()
{
time_t now;
time(&now); // now, czyli teraz, w danej chwili
struct tm beg_of_month;
beg_of_month = *localtime(&now);
// inicjujemy pole struktury na 1 dzien biezacego miesiaca
beg_of_month.tm_hour = 0; // godziny
beg_of_month.tm_min = 0; // minuty
beg_of_month.tm_sec = 0; // sekundy
beg_of_month.tm_mday = 1; // dzien miesiaca
double sekundy = difftime(now, mktime(&beg_of_month));
printf("%.f sekund minelo od poczatku miesiaca.\n", sekundy);
}
// wydruk:
2069081 sekund minelo od poczatku miesiaca.

 

Można łatwo sprawdzić z jaką częstotliwością „tyka” zegar czasu rzeczywistego w naszym systemie.
 
#include <ctime>
#include <iostream>
using namespace std;
int main()
{
cout << "Stala ma wartosc: " << CLOCKS_PER_SEC;
}
// wydruk:
Stala ma wartosc: 1000000
 
Uzyskana tu wartość 1 000 000 oznacza, że nasze pomiary czasu możemy wykonywać taką techniką z dokładnością do jednej mikrosekundy (zegar działa z częstotliwością milion „tyknięć” na sekundę). Wygodna niewątpliwie (użyta w powyższym przykładzie) funkcja difftime() ma tę wadę, że zwraca nam pełne sekundy.