Mam zadanie dopasować liczby zmiennoprzecinkowe. Napisałem dla niego następujące wyrażenie regularne:
[-+]?[0-9]*\.?[0-9]*
Ale zwraca błąd:
Invalid escape sequence (valid ones are \b \t \n \f \r \" \' \\ )
Zgodnie z moją wiedzą musimy również użyć znaku ucieczki .
. Proszę, popraw mnie tam, gdzie się mylę.
(?:\d+(?:\.\d*)?|\.\d+)
i był publikowany w nieskończoność na SO ...[-+]?([0-9]*[.])?[0-9]+([eE][-+]?\d+)?
jeśli chcesz również złapać notację wykładniczą, np. 3.023e-23Odpowiedzi:
TL; DR
Użyj
[.]
zamiast\.
i[0-9]
zamiast,\d
aby uniknąć problemów z ucieczką w niektórych językach (takich jak Java).Dzięki bezimiennemu za pierwotne rozpoznanie tego.
Jednym stosunkowo prostym wzorcem dopasowania liczby zmiennoprzecinkowej jest
To będzie pasować:
123
123.456
.456
Zobacz przykład roboczy
Jeśli chcesz również dopasować
123.
(kropka bez części dziesiętnej), będziesz potrzebować nieco dłuższego wyrażenia:Zobacz odpowiedź pkellera, aby uzyskać pełniejsze wyjaśnienie tego wzoru
Jeśli chcesz uwzględnić liczby niedziesiętne, takie jak szesnastkowe i ósemkowe, zobacz moją odpowiedź na temat Jak rozpoznać, czy ciąg jest liczbą? .
Jeśli chcesz sprawdzić, czy dane wejściowe są liczbą (zamiast znajdować liczbę w danych wejściowych), powinieneś otoczyć wzór znakami
^
i$
, tak jak to:Nieregularne wyrażenia regularne
„Wyrażenia regularne” zaimplementowane w większości nowoczesnych języków, interfejsów API, frameworków, bibliotek itp. Opierają się na koncepcji opracowanej w teorii języka formalnego . Jednak inżynierowie oprogramowania dodali wiele rozszerzeń, które przenoszą te implementacje daleko poza formalną definicję. Tak więc, chociaż większość silników wyrażeń regularnych jest do siebie podobna, w rzeczywistości nie ma standardu. Z tego powodu wiele zależy od tego, jakiego języka, API, frameworka czy biblioteki używasz.
(Nawiasem mówiąc, aby zmniejszyć zamieszanie, wiele miały do korzystania z „ regex ” lub „ regexp ”, aby opisać te ulepszone językach ogłoszeń. See Czy regex samo jak wyrażenie regularne? Na RexEgg.com aby uzyskać więcej informacji.)
To powiedziawszy, większość silników regex (właściwie wszystkie, o ile wiem) zaakceptowałaby
\.
. Najprawdopodobniej jest problem z ucieczką.Kłopoty z ucieczką
Niektóre języki mają wbudowaną obsługę wyrażeń regularnych, na przykład JavaScript . Dla tych języków, które tego nie robią, ucieczka może stanowić problem.
Dzieje się tak, ponieważ zasadniczo kodujesz w języku w języku. Na przykład Java używa
\
jako znaku zmiany znaczenia w swoich ciągach, więc jeśli chcesz umieścić literalny znak ukośnika odwrotnego w ciągu, musisz go zmienić:Jednak wyrażenia regularne również używają
\
znaku do ucieczki, więc jeśli chcesz dopasować znak dosłowny\
, musisz go uciec dla silnika wyrażeń regularnych, a następnie ponownie uciec dla Javy:W twoim przypadku prawdopodobnie nie uniknąłeś znaku ukośnika odwrotnego w języku, w którym programujesz:
Cała ta ucieczka może być bardzo zagmatwana. Jeśli język, z którym pracujesz, obsługuje nieprzetworzone łańcuchy , powinieneś użyć ich, aby zmniejszyć liczbę ukośników odwrotnych, ale nie wszystkie języki obsługują (przede wszystkim Java). Na szczęście istnieje alternatywa, która będzie działać przez jakiś czas:
W przypadku silnika wyrażeń regularnych
\.
i[.]
oznaczają dokładnie to samo. Zauważ, że nie działa to w każdym przypadku, jak nowa linia (\\n
), otwarty nawias kwadratowy (\\[
) i ukośnik odwrotny (\\\\
lub[\\]
).Uwaga dotycząca pasujących liczb
(Podpowiedź: jest trudniej niż myślisz)
Dopasowanie liczby to jedna z tych rzeczy, które uważasz za dość łatwe w przypadku wyrażenia regularnego, ale w rzeczywistości jest to dość trudne. Przyjrzyjmy się Twojemu podejściu, kawałek po kawałku:
Dopasuj opcjonalny
-
lub+
Dopasuj 0 lub więcej kolejnych cyfr
Dopasuj opcjonalne
.
Dopasuj 0 lub więcej kolejnych cyfr
Po pierwsze, możemy trochę wyczyścić to wyrażenie, używając skrótu klasy znaków dla cyfr (zwróć uwagę, że jest to również podatne na wspomniany powyżej problem ze znakami ucieczki):
[0-9]
=\d
Użyję
\d
poniżej, ale pamiętaj, że oznacza to to samo co[0-9]
. (Cóż, w rzeczywistości w niektórych silnikach\d
będą pasować cyfry ze wszystkich skryptów, więc będzie pasować bardziej niż[0-9]
będzie, ale to prawdopodobnie nie ma znaczenia w twoim przypadku).Teraz, jeśli przyjrzysz się temu uważnie, zdasz sobie sprawę, że każda część twojego wzoru jest opcjonalna . Ten wzorzec może pasować do łańcucha o długości 0; ciąg złożony tylko z
+
lub-
; lub ciąg składający się tylko z.
. To prawdopodobnie nie jest to, co zamierzałeś.Aby to naprawić, dobrze jest zacząć od „zakotwiczenia” wyrażenia regularnego za pomocą minimalnego wymaganego ciągu, prawdopodobnie jednej cyfry:
Teraz chcemy dodać część dziesiętną, ale nie idzie to tam, gdzie myślisz:
Będzie to nadal pasowało do wartości takich jak
123.
. Co gorsza, ma w sobie odrobinę zła . Kropka jest opcjonalna, co oznacza, że masz dwie powtarzające się klasy obok siebie (\d+
i\d*
). W rzeczywistości może to być niebezpieczne, jeśli zostanie użyte w niewłaściwy sposób, otwierając system na ataki DoS.Aby to naprawić, zamiast traktować kropkę jako opcjonalną, musimy traktować ją jako wymaganą (aby oddzielić powtarzające się klasy znaków) i zamiast tego uczynić całą część dziesiętną opcjonalną:
Teraz wygląda lepiej. Wymagamy okresu między pierwszą sekwencją cyfr a drugą, ale jest fatalna wada: nie możemy dopasować,
.123
ponieważ wymagana jest teraz cyfra wiodąca.W rzeczywistości jest to dość łatwe do naprawienia. Zamiast uczynić „dziesiętną” część liczby opcjonalną, musimy spojrzeć na nią jako na sekwencję znaków: 1 lub więcej liczb, które mogą być poprzedzone znakiem a,
.
które mogą być poprzedzone 0 lub większą liczbą cyfr:Teraz dodajemy tylko znak:
Oczywiście te ukośniki są dość irytujące w Javie, więc możemy podstawiać w naszych długich klasach znaków:
Dopasowywanie a walidacja
Pojawiło się to kilka razy w komentarzach, więc dodaję dodatek dotyczący dopasowywania i sprawdzania poprawności.
Celem dopasowania jest znalezienie treści w danych wejściowych („igła w stogu siana”). Celem walidacji jest upewnienie się, że dane wejściowe mają oczekiwany format.
Regeksy z natury pasują tylko do tekstu. Biorąc pod uwagę pewne dane wejściowe, albo znajdą pasujący tekst, albo nie. Jednak poprzez „przyciąganie” wyrażenia do początku i końca danych wejściowych za pomocą znaczników kotwicy (
^
i$
), możemy zapewnić, że żadne dopasowanie nie zostanie znalezione, chyba że całe dane wejściowe będą pasować do wyrażenia, efektywnie wykorzystując wyrażenia regularne do walidacji .Wyrażenie regularne opisane powyżej (
[+-]?([0-9]*[.])?[0-9]+
) dopasuje jedną lub więcej liczb w ciągu docelowym. Więc biorąc pod uwagę dane wejściowe:Regex będą pasować
1.34
,7.98
,1.2
,.3
i.4
.Aby sprawdzić, czy dane wejściowe są liczbą, a jedynie liczbą, „przyciągnij” wyrażenie na początek i na koniec danych wejściowych, zawijając je w znaczniki kotwicy:
Spowoduje to znalezienie dopasowania tylko wtedy, gdy całe wejście jest liczbą zmiennoprzecinkową, i nie znajdzie dopasowania, jeśli wejście zawiera dodatkowe znaki. Tak więc, biorąc pod uwagę dane wejściowe
1.2
, zostanie znalezione dopasowanie, ale pod warunkiem, żeapple 1.2 pear
żadne dopasowania nie zostaną znalezione.Zauważ, że niektóre silniki regex mają
validate
,isMatch
lub podobną funkcję, która w zasadzie robi to, co Opisałem automatycznie, wracająctrue
jeśli zostanie znaleziony, afalse
jeśli nie zostanie znaleziony. Pamiętaj również, że niektóre silniki pozwalają na ustawienie flag, które zmieniają definicję^
i$
, dopasowując początek / koniec linii zamiast początku / końca całego wejścia. Zwykle nie jest to ustawienie domyślne, ale uważaj na te flagi.źródło
\d+(\.\d*)?|\.\d+
/[-+]?(\d*[.])?\d+/.test("1.bc") // returns true
1.
pasuje. Dodaj^
i$
na początku i na końcu wyrażenia regularnego, jeśli chcesz dopasować tylko wtedy, gdy całe dane wejściowe są zgodne.[-+]?(([0-9]*[.]?[0-9]+([ed][-+]?[0-9]+)?)|(inf)|(nan))
zmiennoprzecinkowe mogą mieć wykładniki lub być NaN / Inf, więc użyłbym tego:, e / d dla liczby zmiennoprzecinkowej / podwójnej precyzji. Nie zapomnij flagi spasowania do wyrażenia regularnegoNie sądzę, aby którakolwiek z odpowiedzi na tej stronie w momencie pisania była poprawna (również wiele innych sugestii w innych miejscach na SO jest błędnych). Trudność polega na tym, że musisz dopasować wszystkie poniższe możliwości:
0.35
,22.165
)0.
,1234.
).0
,.5678
)Jednocześnie musisz upewnić się, że gdzieś jest co najmniej jedna cyfra, czyli niedozwolone są:
+.
lub-.
)+
lub-
samodzielnieNa początku wydaje się to trudne, ale jednym ze sposobów znalezienia inspiracji jest przyjrzenie się źródłu OpenJDK dla
java.lang.Double.valueOf(String)
metody (zacznij od http://hg.openjdk.java.net/jdk8/jdk8/jdk , kliknij "Przeglądaj", przejdź w dół/src/share/classes/java/lang/
i znajdźDouble
klasę). Długi regex, który zawiera ta klasa, uwzględnia różne możliwości, o których OP prawdopodobnie nie miał na myśli, ale ignoruje dla uproszczenia części, które dotyczą NaN, nieskończoności, notacji szesnastkowej i wykładników, i używa\d
zamiast notacji POSIX dla pojedynczej cyfry, mogę zredukować ważne części wyrażenia regularnego dla liczby zmiennoprzecinkowej ze znakiem bez wykładnika do:[+-]?((\d+\.?\d*)|(\.\d+))
Nie sądzę, aby można było uniknąć
(...)|(...)
konstrukcji bez dopuszczenia czegoś, co nie zawiera cyfr, lub zakazania jednej z możliwości, która nie ma cyfr przed kropką dziesiętną lub żadnych cyfr po niej.Oczywiście w praktyce będziesz musiał uwzględnić końcowe lub poprzedzające białe znaki, albo w samym wyrażeniu regularnym, albo w kodzie, który go używa.
źródło
123.
, to tak ... przełącznik lub jest jedynym rozwiązaniem, jak wskazałem w komentarzu do mojego oryginalnego postu.[+-]?((?=\.?\d)\d*\.?\d*)
można użyć wyrażenia regularnego, aby uniknąć zmiany? Używapotrzebujesz:
Uniknąłem znaku „+” i „-”, a także zgrupowałem ułamek dziesiętny z następującymi po nim cyframi, ponieważ coś w rodzaju „1”. nie jest prawidłową liczbą.
Zmiany pozwolą ci dopasować liczby całkowite i zmiennoprzecinkowe. na przykład:
źródło
.1
że nie byłoby to dozwolone, mimo że takie dane wejściowe są powszechnie uznawane za poprawne.-
i+
, które nie są liczbami. Regex jest trudny! :)\.
nie działa.Chcę dopasować, które większość języków uważa za prawidłowe liczby (liczby całkowite i zmiennoprzecinkowe):
'5' / '-5'
'1.0' / '1.' / '.1' / '-1.' / '-.1'
'0.45326e+04', '666999e-05', '0.2e-3', '-33.e-1'
Uwagi:
preceding sign of number ('-' or '+') is optional
'-1.' and '-.1' are valid but '.' and '-.' are invalid
'.1e3' is valid, but '.e3' and 'e3' are invalid
Aby wspierać oba „1”. i „.1” potrzebujemy operatora OR („|”), aby upewnić się, że wykluczamy „.” od dopasowania.
[+-]?
+/- sing jest opcjonalne, ponieważ?
oznacza 0 lub 1 dopasowania(
ponieważ mamy 2 wyrażenia podrzędne, musimy je umieścić w nawiasach\d+([.]\d*)?(e[+-]?\d+)?
Dotyczy to liczb zaczynających się od cyfry|
oddziela wyrażenia podrzędne[.]\d+(e[+-]?\d+)?
dotyczy to numerów zaczynających się od „.”)
koniec wyrażeń[.]
pierwszy znak to kropka (w nawiasach lub w innym przypadku jest to symbol wieloznaczny)\d+
jedna lub więcej cyfr(e[+-]?\d+)?
jest to opcjonalna notacja naukowa (0 lub 1 trafień ze względu na końcówkę „?”)\d+
jedna lub więcej cyfr([.]\d*)?
opcjonalnie możemy mieć kropkę, a po niej zero lub więcej cyfr(e[+-]?\d+)?
jest to opcjonalna notacja naukowae
literał, który określa wykładnik[+-]?
opcjonalny znak potęgi\d+
jedna lub więcej cyfrWszystkie razem:
Aby również zaakceptować
E
:( Przypadki testowe )
źródło
To proste: użyłeś Javy i powinieneś użyć
\\.
zamiast\.
(szukaj znaków ucieczki w Javie).źródło
Ten pracował dla mnie:
Możesz również użyć tego (bez nazwanego parametru):
Użyj testera regex online, aby go przetestować (np. Regex101)
źródło
To będzie pasować:
źródło
[+-]?
- opcjonalny znak wiodący(([1-9][0-9]*)|(0))
- liczba całkowita bez wiodącego zera, w tym pojedyncze zero([.,][0-9]+)?
- opcjonalna część ułamkowaźródło
W C ++ przy użyciu biblioteki regex
Odpowiedź wyglądałaby tak:
Zauważ, że nie biorę symbolu znaku, gdybyś chciał go z symbolem znaku, to by to dotyczyło:
To również oddziela zwykłą liczbę lub liczbę dziesiętną.
źródło
W notacji c liczba zmiennoprzecinkowa może mieć następujące kształty:
Aby utworzyć zmiennoprzecinkowe wyrażenie regularne, najpierw utworzę „zmienną wyrażenia regularnego int”:
Teraz napiszę małe fragmenty wyrażenia regularnego typu float - rozwiązaniem jest połączenie tych fragmentów za pomocą symbolu „|”.
Kawałki:
Ostateczne rozwiązanie (łączenie małych kawałków):
źródło
Wypróbuj to rozwiązanie.
źródło
dla javascript
Co zadziała dla 1,23 1234,22 0 0,12 12
Możesz zmienić części w,
{}
aby uzyskać różne wyniki w długości i początku części dziesiętnej. Jest to używane w wejściach do wprowadzania liczby i sprawdzania każdego wejścia podczas wpisywania, zezwalając tylko na to, co się powiedzie.źródło