Wyszukiwanie int i double za pomocą std::regex

0

Hej!

Byłabym wdzięczna za wskazanie błędu, czemu poniższy kod nie wyszukuje dopasowanych ciągów idea jest taka by wyszukiwał inty lub double a także operatory arytmetyczne, podane wyrażenie chcę rozdzielić na poszczególne tokeny. Druga sprawa czy sam iterator wystarczy w celu przejścia przez wszystkie wyodrębione tokeny czy muszę zapisywać je w jakimś kontenerze. Wolałabym jeżeli dałoby się nie tworzyć dodatkowego kontenera, ponieważ chodzi mi tylko o odczytanie dopasowań a na ich podstawie dalsza obróbka tu jest tworzenie obiektów odp klas w zależności od odczytanego wyrażenia:

	std::string line = "- + - -87.09 6 -34";
	std::regex pattern("[-\+]?(\d+)(\.((\d+)?)?)|[*\-+^\/]",std::regex::icase);
	std::copy(std::sregex_token_iterator(line.begin(), line.end(), pattern, 1),
		std::sregex_token_iterator(),
		std::ostream_iterator<std::string>(std::cout, "\n"));

1

Nie znam się na C++, ale jeżeli wyrażenia regularne w tym języku nie odbiegają od standardów, to podane wyrażenie [-\+]?(\d+)(\.((\d+)?)?)|[*\-+^\/] ja bym rozpisał słownie. Jeżeli w std::regex kolejność operatorów jest taka, jak napisane na stronie https://www.regular-expressions.info/alternation.html: "The alternation operator has the lowest precedence of all regex operators", to idzie to tak:

  1. Dopasuj albo wyrażenie (A) [-\+]?(\d+)(\.((\d+)?)?), albo wyrażenie (B) [*\-+^\/]. Następnie:
  2. Wyrażenie (A) [-\+]?(\d+)(\.((\d+)?)?) odczytałbym: albo dopasuj dokładnie jeden znak -, albo dokładnie jeden znak +, albo żadnego z nich nie dopasowuj ([-\+]?), za którym stoi przynajmniej jedna liczba (\d+), za którą stoi dokładnie jedna kropka (\.), za którą albo stoi ciąg cyfr o przynajmniej jednej cyfrze, albo nie stoi żaden taki ciąg. Wyrażenie ((\d+)?)? w moim odczuciu ma niepotrzebny znak zapytania (razem z grupą przechwytującą), bo sprowadza się do wyrażenia (\d+)? – ale jeszcze to przetestuj, nie jestem ekspertem.
  3. Wyrażenie (B) [*\-+^\/] odczytałbym: dopasuj albo znak *, albo -, albo +, albo ^, albo /. Jeśli w przypadku std::regex wszystkie znaki w nawiasach kwadratowych są domyślnie escapowane, to najprawdopodobniej dochodzi do tego jeszcze znak \ (i wtedy niepotrzebny byłby ów znak we fragmencie \-) (skreśliłem, bo najprawdopodobniej jednak ten znak trzeba by jeszcze escapować dodatkowo).

Pominąłem opisy grup przechwytujących.


UPDATE:

Nie działa dlatego, że w obecnej wersji obowiązkowe są cyfry po kropce.

By podany przykład (- + - -87.09 6 -34) został dopasowany w całości (choć nie wiem, czy poprawnie) – przynajmniej z wyrażeniami regularnymi typu PCRE – powinnaś dodać jeszcze znak zapytania po wyrażeniu (\.((\d+)?)?). Czyli całość będzie wyglądać tak: [-\+]?(\d+)(\.((\d+)?)?)?|[*\-+^\/]

0

Kurcze dzięki wielkie za analizę, właśnie jak pisałam ten kod to miało działać tak jak rozpisałeś :D ale jak debbuguje to w patternResult są śmieci i brak jakiegokolwiek dopasowania :( zmieniłam z iteratora na:

	std::smatch patternResult;
	while (std::regex_search(line, patternResult, pattern)) {
		//for (auto x : patternResult) std::cout << x << " ";
		line = patternResult.suffix().str();

ale to nic nie zmienia.

0

Pomogłeś przeogromnie bo zadziałało! jedyna podejrzana sprawa jest taka, że zamienia mi kolejność operatorów - i + i + wczytywany jest na samym początku... ale w ogóle się wczytuje więc naprawdę jestem wdzięczna, dzięki wielkie :D

0

"- + - -87.09 6 -34"

Co stoi na przeszkodzie do wykorzystania białych znaków?

>>> s = '- + - -87.09 6 -34'

>>> s.split()
['-', '+', '-', '-87.09', '6', '-34']

>>> re.split('\s+', s)
['-', '+', '-', '-87.09', '6', '-34']

>>> re.findall('\S+', s)
['-', '+', '-', '-87.09', '6', '-34']

>>> 

Czyli całość będzie wyglądać tak:[-\+]?(\d+)(\.((\d+)?)?)?|[*\-+^\/]

Kek. O to chodziło: [+-]?\d+\.?\d*|[*+\-^/]? To wyrażenie nie złapie .42.

0

@Mózg tak bardzo skupiłam się na tym aby wyodrębnić stricte wszystkie znaki poza białymi, że nie zwróciłam uwagi na możliwość użycia właśnie białych w celu wyodrębnienia wszystkich innych, dzięki wielkie dokładnie o to chodziło! jeżeli chciałabym aby działało dla wyrażeń, np. .42 dodaje [+-]?\d+.?\d*|[*+-^]|.\d+ czy da się to bardziej wyszukanie napisać w środku pierwszej alternatywy? Próbowałam z '?' ale wtedy rozdziela mi liczbę zmiennoprzecinkową na dwie odrębne liczby bo nie widzi kropki. A wiesz może jak "przechodzić" po wszystkich zwróconych dopasowaniach z podanej linii? Chciałabym odczytywać każde poj dopasowanie i na jego podstawie tworzyć obiekty odp klas. Czy za pomocą iteratora czy muszę umieścić wyniki w jakimś kontenerze?

0
Leks napisał(a):

jeżeli chciałabym aby działało dla wyrażeń, np. .42 dodaje [+-]?\d+.?\d*|[*+-^]|.\d+ czy da się to bardziej wyszukanie napisać w środku pierwszej alternatywy? Próbowałam z '?' ale wtedy rozdziela mi liczbę zmiennoprzecinkową na dwie odrębne liczby bo nie widzi kropki.

Co rozumiesz przez "w środku pierwszej alternatywy"?

0

To znaczy tutaj: [+-]?\d+.?\d*

0

No tak, tylko w takim razie jakie wyszukiwanie chcesz tam wstawić?

0

właśnie nie wiem jakbym miała je zmodyfikować aby odejmowało też liczby tj: .43322 etc ja bym chyba została przy dopisaniu tego jako trzeciej alternatywy

0

Biorąc wyrażenie @Mózg za bazę, należy ująć cyfry części całkowitej w nawiasy () (tworząc grupę) i zrobić ją opcjonalną, czyli tak: [+-]?(\d+)?\.?\d*|[*\-+^\/].

PS. Moje niedopatrzenie – to powyżej jest oczywiście poprawnie, ale można zrobić to prościej, zamieniając w oryginalnym @Mózg-owym wyrażeniu + (1 lub więcej) na * (0 lub więcej): [+-]?\d*\.?\d*|[*\-+^\/]. Możesz sprawdzić na stronie https://regexr.com/ W tej sytuacji mój dodatek "UDPATE2" poniżej traci na znaczeniu. ;)

PS2. Oczywiście podtrzymuję, ze std::regex może mieć troszkę inną implementację wyrażeń regularnych od ogólnych standardów i powinnaś to sprawdzić (w miarę możliwości w jakiejś uproszczonej dokumentacji, nie musisz czytać kodu źródłowego ;) ).


UPDATE:

Ale pamiętaj przy tworzeniu wyrażeń regularnych: to broń obosieczna. Niedokładne wyrażenie może nie dopasować Ci oczekiwanych ciągów znaków, ale za to może dopasować coś całkiem nieprzewidywalnego. Ekspertem nie jestem, ale zalecałbym zawsze testowanie zarówno dla przypadków poprawnych, jak i błędnych.

PS. Tzn. każde wyrażenie coś dopasuje ;), ale "nieprzewidywalnego" w sensie – tekst, który masz, a nie powinien zostać dopasowany.


UPDATE2:

Grupa może być przechwytująca – (wyrażenie), albo nieprzechwytująca – (?:wyrażenie). Myślę jednak, że w tym wypadku nie ma to znaczenia. Jeśli chodzi o wydajność, nieprzechwytująca jest szybsza.

0

[+-]?\d*\.?\d*|[*\-+^\/]

Teraz nie łapiesz *, /, ^ (łapiesz puste ciągi).

1

Postanowiłem napisać wyrażenie dla liczb całkowitych na podstawie specyfikacji C++: https://en.cppreference.com/w/cpp/language/integer_literal Dla liczb zmiennoprzecinkowych później spróbuję.

([1-9][0-9]*|0[xX][0-9a-fA-F]+|0[bB][0-1]+|0[0-7]*)(u[lL]{0,2}|U[lL]{0,2}|[lL]{0,2}u|[lL]{0,2}U|l{1,2}|L{1,2})?

Składa się z alternatywy czterech grup znaków – reprezentacji liczby w różnych systemach, w kolejności:

  • dziesiętna: [1-9][0-9]*
  • szesnastkowa: 0[xX][0-9a-fA-F]+
  • binarna: 0[bB][0-1]+
  • ósemkowa: 0[0-7]*

oraz z przyrostka składającego się z kombinacji małych i wielkich liter u oraz l (dla "kombinacji" typów C++ long oraz unsigned): (u[lL]{0,2}|U[lL]{0,2}|[lL]{0,2}u|[lL]{0,2}U|l{1,2}|L{1,2})?

Najprawdopodobniej nie jest to napisane optymalnie w kontekście wydajności, ale celowałem w prostotę czytania ("prostotę" w kontekście wyrażeń regularnych). To wyrażenie dopasowuje na pewno poniższe liczby:

123 0123 0x123 0b10

Ostatnia grupa – przyrostki u oraz l – jest dość rozbudowana. Nie wiedziałem, jak napisać to prościej. Ale dopasowuje wszystkie poniższe kombinacje (mam nadzieję, że żadnej nie brakuje do kompletu, i mam nadzieję, że nie łapie więcej...):

0u 0l 0U 0L
0ll 0LL
0ul 0uL 0Ul 0UL
0lu 0Lu 0lU 0LU
0ull 0uLL 0ulL 0uLl 0Ull 0ULL 0UlL 0ULl
0llu 0LLu 0lLu 0Llu 0llU 0LLU 0lLU 0LlU

Należy pamiętać, że:

  • (UPDATE6) Wyrażenie było testowane na silniku PCRE. Nie wiem, czy będzie działać tak samo w C++. Może w ogóle być niepoprawne.
  • Wyrażenie nie było testowane dla niepoprawnych kombinacji znaków. Należy przetestować.
  • Wyrażenie było testowane jedynie dla powyższych kombinacji znaków. Jeżeli są możliwe jakieś inne (myślę, że nie, ale ja się często mylę), należy przetestować dla nich.
  • Niektóre sekwencje cyfr – np. 0 – mogą zostać zinterpretowane jako liczby w kilku reprezentacjach naraz, np. jako dziesiętna ORAZ ósemkowa. C++ ma na pewno jakąś kolejność interpretacji – jeśliby miało to znaczenie, należałoby zamienić odpowiednie grupy w pierwszej części wyrażenia miejscami. Jednak należy zauważyć, że w obecnej wersji wyrażenia pewna kolejność JEST wymagana – np. fragmenty dopasowujące liczbę szesnastkową oraz ósemkową MUSZĄ występować przed fragmentem dopasowującym liczbę ósemkową, bo inaczej np. przy wyrażeniu 0x4 dopasuje 0 oraz 4 jako dwa wyrażenia ósemkowe dwie liczby dziesiętne, a nie całość jako wyrażenie liczbę szesnastkową (oczywiście, jeżeli fragment dopasowujący liczbę ósemkową byłby przed fragmentem dopasowującym liczbę dziesiętną, to całe wyrażenie dopasowałoby liczbę ósemkową).
  • Standard C++14 mówi, że w liczbie całkowitej (oraz zmiennoprzecinkowej) może między cyframi występować znak ' (apostrof) – jest ignorowany przez kompilator. :) :) Zdecydowałem się ich nie umieszczać w wyrażeniu, byłoby zbyt skomplikowane do czytania, a poza tym nie byłem pewien, jak dokładnie powinny występować. Zawsze można je dodać.
  • (UPDATE2) To wyrażenie regularne nie zawiera operatorów jednoargumentowych + oraz - (stawianych przed liczbą). Dla samych liczb wystarczy dodać je na początek; natomiast jeśli cała liczba pojawia się w wyrażeniu (tzn. expression, nie regular expression) i może ono zawierać białe znaki między liczbami i operatorami, to sposób dopasowania operatorów jednoargumentowych może być dość skomplikowany.
  • (UPDATE5) Dla czytelności, wyrażenie ma grupy przechwytujące – (), zamiast nieprzechwytujących – (?:). Jeśli potrzeba by Ci było, @Leks, zmiany, to wystarczy dodać ?: po każdym nawiasie otwierającym. Uważam, że dopóki wyrażenie nie ma dopasowywać fragmentów tekstu o dużej liczbie znaków (1000? 10000? 100000?), czytelność jest ważniejsza niż wydajność. Zresztą w przypadku dużej liczby znaków w ogóle odszedłbym od wyrażenia regularnego na rzecz parsera.

(UPDATE3) Komentarz: jak było to podnoszone nawet niedawno na tym forum, wyrażenia regularne mogą nie być najlepszym wyborem umieszczone w kodzie programu. Patrz https://4programmers.net/Forum/1576686 oraz komentarze (swoją drogą, w tym wątku jest kilka ciekawych źródeł dot. wyrażeń regularnych). Osobiście uważam, że w przypadku rozbudowanych wyrażeń regularnych – jakkolwiek mogą być ładnie czy sprytnie napisane – bardzo trudno zweryfikować ich poprawność. Najprawdopodobniej lepiej zamienić takie rozbudowane wyrażenie na parser. Jeśli chodzi o wygodne ich użycie, mnie samemu wygodnie korzysta się z prostych wyrażeń regularnych w silnikach wyszukiwania (np. gdy szukam jakichś fragmentów w plikach źródłowych – o ile dane IDE ma taką opcję).

PS. @Mózg, nie miałbyś nic przeciwko sprawdzeniu, czy gdzieś nie pomyliłem się? :)


UPDATE:
Usunąłem niepotrzebne nawiasy w reprezentacji dziesiętnej.


UPDATE4:
Zamieniłem fragment \d na [0-9] we fragmencie dopasowującym liczbę dziesiętną, dla spójności z fragmentami dopasowującymi pozostałe reprezentacje liczbowe.

0

Bardzo, bardzo, bardzo Wam dziękuję za odpowiedzi, uczelnia mnie wzywała więc dzisiaj dopiero mogłam znowu do tego siąść; jestem ogromnie wdzięczna @Silv za poświęcony czas i rozpisanie wyrażenia dla liczb całkowitych w różnych systemach! Biorę się do testowania. Ogólna moja wizja była taka że właśnie buduje parser :D a regexów używam do porównania czy w przychodzącym wyrażeniu arytmetycznym zapisanym w odpowiedniej notacji nie ma niewłaściwych znaków a później za ich pomocą (tych odp regexów) podzielenie stringa na tokeny i stworzenie obiektów odpowiednich klas, np. klasy plus, minus, liczba etc i analiza składniowa (drzewo rozbioru).

0

Postanowiłem spróbować napisać wyrażenia regularne dla liczb zmiennoprzecinkowych. Materiał, na podstawie którego piszę, to: https://en.cppreference.com/w/cpp/language/floating_literal

Od razu disclaimer: Piszę to nie bezpośrednio na podstawie standardu, a jedynie na podstawie materiału napisanego na jego podstawie (https://en.cppreference.com/) – toteż należałoby jeszcze bezpośrednio sprawdzić zgodność ze standardem (standard dostępny jest za opłatą: https://isocpp.org/std/the-standard).

UPDATE: Poza standardem dostępnym za opłatą, jest jeszcze szkic (draft) jego najnowszej wersji, dostępny za darmo na GitHubie: https://github.com/cplusplus/draft. Są to źródła napisane w LaTeXu, dlatego też żeby zobaczyć wynikowy dokument PDF w pełnej okazałości, należy zainstalować dodatkowe oprogramowanie oraz zbudować projekt (wszystko wyjaśnione w README).

Żeby mieć jakiś track record, będę systematycznie edytował ten post (zamiast pisać wszystko od razu). Postanowiłem podzielić całość na takie warianty, jakie są wyróżnione na cppreference.com. Wyrażenia regularne sprawdzam za pomocą narzędzia https://regexr.com/. Wspomagam się kompilatorem C++ dostępnym online: https://ideone.com/ oraz stroną https://www.wolframalpha.com/. Wszystkie wyrażenia regularne były sprawdzane dla składni PCRE. Przyjąłem, że nie będę uwzględniać opcjonalnego separatora liczb ` (backquote, backgrave lub backtick, a po polsku, hm... nie znam odpowiednika nazw używanych w informatyce; w językoznawstwie, jako symbol akcentu, nazywa się "grawis").

Wariant (1)

Na pierwszy ogień idzie wariant o następującej składni: digit-sequence exponent suffix(optional).

Wyrażenie regularne:

[0-9]+[eE][+-]?[0-9]+[fFlL]?

gdzie:

  • [0-9]+ to digit sequence,
  • [eE][+-]?[0-9]+ to exponent (zapisywany w tzw. scientific E-notation),
  • [fFlL]? to suffix(optional).

To wyrażenie z sukcesem dopasowuje następujące liczby:

0e5 0e5f 0e5F 0e5l 0e5L
0E5 0E5f 0E5F 0E5l 0E5L
0e+5 0e+5f 0e+5F 0e+5l 0e+5L
0E+5 0E+5f 0E+5F 0E+5l 0E+5L

(Swoją drogą, wszystkie podane liczby są równe 0).

W razie wątpliwości – tak, w tym wariancie nie ma kropki (co mnie trochę niepokoi – dlaczego C++ miałby uznawać liczbę bez części dziesiętnej za zmiennoprzecinkową?).

Wariant (2)

Na drugi ogień idzie wariant o następującej składni: digit-sequence . exponent(optional) suffix(optional).

Wyrażenie regularne:

[0-9]+\.([eE][+-]?[0-9]+)?[fFlL]?

gdzie:

  • [0-9]+ to digit sequence,
  • \. to separator (tutaj – kropka dziesiętna; dla liczby w reprezentacji szesnastkowej oczywiście nie dziesiętna),
  • ([eE][+-]?[0-9]+)? to exponent(optional),
  • [fFlL]? to suffix(optional).

To wyrażenie z sukcesem dopasowuje następujące liczby:

0. 0.f 0.F 0.l 0.L
0.e5 0.e5f 0.e5F 0.e5l 0.e5L
0.E5 0.E5f 0.E5F 0.E5l 0.E5L
0.e+5 0.e+5f 0.e+5F 0.e+5l 0.e5L
0.E+5 0.E+5f 0.E+5F 0.E+5l 0.E+5L

Pamiętaj, że poza składnią C++ – w zależności od przyjętej notacji w danym języku – separatorem może być także przecinek lub inny znak, występujący w piśmie, w którym zapisywany jest dany język. Zobacz także: https://en.wikipedia.org/wiki/Radix_point (Ponownie, wszystkie liczby są równe 0).

Wariant (3)

Następnie idzie wariant o takiej składni: digit-sequence(optional) . digit-sequence exponent(optional) suffix(optional).

Wyrażenie regularne:

[0-9]*\.[0-9]+([eE][+-]?[0-9]+)?[fFlL]?

gdzie:

  • [0-9]* to digit-sequence(optional),
  • \. to separator,
  • [0-9]+ to digit-sequence,
  • ([eE][+-]?[0-9]+)? to exponent(optional),
  • [fFlL]? to suffix(optional).

To wyrażenie z sukcesem dopasowuje następujące liczby:

.7 .7f .7F .7l .7L
.7e5 .7e5f .7e5F .7e5l .7e5L
.7E5.7E5f .7E5F .7E5l .7E5L
.7e+5 .7e+5f .7e+5F .7e+5l .7e5L
.7E+5 .7E+5f .7E+5F .7E+5l .7E+5L
0.7 0.7f 0.7F 0.7l 0.7L
0.7e5 0.7e5f 0.7e5F 0.7e5l 0.7e5L
0.7E5 0.7E5f 0.7E5F 0.7E5l 0.7E5L
0.7e+5 0.7e+5f 0.7e+5F 0.7e+5l 0.7e5L
0.7E+5 0.7E+5f 0.7E+5F 0.7E+5l 0.7E+5L

Ten wariant różni się od poprzedniego (nr 2) tym, że poprzedni uwzględniał tylko liczby bez części ułamkowej, a z wymaganą częścią całkowitą (tj. np. "5."), podczas gdy w tym wariancie część ułamkowa musi być, a część całkowita jest opcjonalna (tj. np. "5." lub "5.2"). (Podane przykładowe liczby z "E-notacją" są równe 70000, a bez niej są równe 0.7).

Wariant (4)

W tym wariancie liczba jest w systemie szesnastkowym, a jej składnia odpowiada składni z wariantu nr 1 (który opisuje liczbę w systemie dziesiętnym). Liczba ma taką składnię: 0x | 0X hex-digit-sequence exponent suffix(optional).

Wyrażenie regularne:

0[xX][0-9a-fA-F]+[pP][+-]?[0-9]+[fFlL]?

gdzie:

  • 0[xX] to tzw. przedrostek szesnastkowy (ang. hexadecimal prefix; tutaj możliwe powody, dlaczego składa się akurat ze znaków "0" oraz "x"),
  • [0-9a-fA-F]+ to hex-digit-sequence,
  • [pP][+-]?[0-9]+ to exponent,
  • [fFlL]? to suffix(optional).

To wyrażenie z sukcesem dopasowuje następujące liczby:

0xA9p3 0xA9p3f 0xA9p3F 0xA9p3l 0xA9p3L
0xA9P3 0xA9P3f 0xA9P3F 0xA9P3l 0xA9P3L
0xA9p+3 0xA9p+3f 0xA9p+3F 0xA9p+3l 0xA9p+3L
0xA9P+3 0xA9P+3f 0xA9P+3F 0xA9P+3l 0xA9P+3L
0XA9p3 0XA9p3f 0XA9p3F 0XA9p3l 0XA9p3L
0XA9P3 0XA9P3f 0XA9P3F 0XA9P3l 0XA9P3L
0XA9p+3 0XA9p+3f 0XA9p+3F 0XA9p+3l 0XA9p+3L
0XA9P+3 0XA9P+3f 0XA9P+3F 0XA9P+3l 0XA9P+3L

Wartość części exponent – tj. [0-9]+ w tym wariancie – nie może być szesnastkowa (tj. musi składać się z ciągu cyfr od 0 do 9, czyli właśnie [0-9]+). Uwaga: ta wartość jest traktowana jako wartość binarna (a nie np. szesnastkowa). Cytat z https://en.cppreference.com/w/cpp/language/floating_literal:

For a hexadecimal floating literal, the significand is interpreted as a hexadecimal rational number, and the digit-sequence of the exponent is interpreted as the integer power of 2 to which the significand has to be scaled.

double d = 0x1.2p3; // hex fraction 1.2 (decimal 1.125) scaled by 2^3, that is 9.0


## Wariant (5)

W tym wariancie liczba jest w systemie szesnastkowym, a jej składnia odpowiada składni z wariantu nr 2 (który opisuje liczbę w systemie dziesiętnym) – z tym, że _exponent_ **nie** jest opcjonalny. Liczba ma taką składnię: _**0x** | **0X** hex-digit-sequence . exponent suffix(optional)_.

Wyrażenie regularne:

0[xX][0-9a-fA-F]+.[pP][+-]?[0-9]+[fFlL]?

gdzie:
- `0[xX]` to przedrostek szesnastkowy,
- `[0-9a-fA-F]+` to _hex-digit-sequence_,
- `\.` to separator,
- `[pP][+-]?[0-9]+` to _exponent_,
- `[fFlL]?` to _suffix(optional)_.

To wyrażenie z sukcesem dopasowuje następujące liczby:

0x0.p5 0x0.p5f 0x0.p5F 0x0.p5l 0x0.p5L
0x0.P5 0x0.P5f 0x0.P5F 0x0.P5l 0x0.P5L
0x0.p+5 0x0.p+5f 0x0.p+5F 0x0.p+5l 0x0.p5L
0x0.P+5 0x0.P+5f 0x0.P+5F 0x0.P+5l 0x0.P+5L
0X0.p5 0X0.p5f 0X0.p5F 0X0.p5l 0X0.p5L
0X0.P5 0X0.P5f 0X0.P5F 0X0.P5l 0X0.P5L
0X0.p+5 0X0.p+5f 0X0.p+5F 0X0.p+5l 0X0.p5L
0X0.P+5 0X0.P+5f 0X0.P+5F 0X0.P+5l 0X0.P+5L


## Wariant (6)

W tym wariancie liczba jest w systemie szesnastkowym, a jej składnia odpowiada składni z wariantu nr 3 (który opisuje liczbę w systemie dziesiętnym) – z tym, że _exponent_ **nie** jest opcjonalny. Liczba ma taką składnię: _**0x** | **0X** hex-digit-sequence(optional) . hex-digit-sequence exponent suffix(optional)_.

Wyrażenie regularne:

0[xX][0-9a-fA-F]*.[0-9a-fA-F]+[pP][+-]?[0-9]+[fFlL]?

gdzie:
- `0[xX]` to przedrostek szesnastkowy,
- `[0-9a-fA-F]*` to _hex-digit-sequence(optional)_,
- `\.` to separator,
- `[0-9a-fA-F]+` to _hex-digit-sequence_,
- `[pP][+-]?[0-9]+` to _exponent_,
- `[fFlL]?` to _suffix(optional)_.

To wyrażenie z sukcesem dopasowuje następujące liczby:

0x.D7p5 0x.D7p5f 0x.D7p5F 0x.D7p5l 0x.D7p5L
0x.D7P5 0x.D7P5f 0x.D7P5F 0x.D7P5l 0x.D7P5L
0x.D7p+5 0x.D7p+5f 0x.D7p+5F 0x.D7p+5l 0x.D7p5L
0x.D7P+5 0x.D7P+5f 0x.D7P+5F 0x.D7P+5l 0x.D7P+5L
0x0.D7p5 0x0.D7p5f 0x0.D7p5F 0x0.D7p5l 0x0.D7p5L
0x0.D7P5 0x0.D7P5f 0x0.D7P5F 0x0.D7P5l 0x0.D7P5L
0x0.D7p+5 0x0.D7p+5f 0x0.D7p+5F 0x0.D7p+5l 0x0.D7p5L
0x0.D7P+5 0x0.D7P+5f 0x0.D7P+5F 0x0.D7P+5l 0x0.D7P+5L


## Uwagi końcowe

Mam nadzieję, że nigdzie się nie pomyliłem. **Jest to bardzo prawdopodobne**, bo to jednak analiza leksykalna – coś, co powinien wykonywać komputer (tj. lekser). Jeśli kto zauważy błąd, proszę o wskazanie miejsca.

1 użytkowników online, w tym zalogowanych: 0, gości: 1