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
[+-]?([0-9]*[.])?[0-9]+
To będzie pasować:
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:
[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)
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:
^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$
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ć:
// creates a single character string: "\"
String x = "\\";
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:
// Creates a two-character string: "\\"
// When used as a regex pattern, will match a single character: "\"
String regexPattern = "\\\\";
W twoim przypadku prawdopodobnie nie uniknąłeś znaku ukośnika odwrotnego w języku, w którym programujesz:
// will most likely result in an "Illegal escape character" error
String wrongPattern = "\.";
// will result in the string "\."
String correctPattern = "\\.";
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:
String correctPattern = "[.]";
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+
[0-9]*
Dopasuj 0 lub więcej kolejnych cyfr
\.?
Dopasuj opcjonalne .
[0-9]*
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:
\d+
Teraz chcemy dodać część dziesiętną, ale nie idzie to tam, gdzie myślisz:
\d+\.?\d* /* This isn't quite correct. */
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ą:
\d+(\.\d+)? /* Better. But... */
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:
(\d*\.)?\d+
Teraz dodajemy tylko znak:
[+-]?(\d*\.)?\d+
Oczywiście te ukośniki są dość irytujące w Javie, więc możemy podstawiać w naszych długich klasach znaków:
[+-]?([0-9]*[.])?[0-9]+
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:
apple 1.34 pear 7.98 version 1.2.3.4
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:
^[+-]?([0-9]*[.])?[0-9]+$
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, że apple 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ąc true
jeśli zostanie znaleziony, a false
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.