TL; DR
Verwenden Sie [.]
anstelle von \.
und [0-9]
anstelle von \d
, um zu vermeiden, dass Probleme in einigen Sprachen (wie Java) vermieden werden.
Vielen Dank an den Namenlosen , der dies ursprünglich erkannt hat.
Ein relativ einfaches Muster zum Abgleichen einer Gleitkommazahl ist
[+-]?([0-9]*[.])?[0-9]+
Dies wird übereinstimmen:
Siehe ein Arbeitsbeispiel
Wenn Sie auch übereinstimmen möchten 123.
(ein Punkt ohne Dezimalteil), benötigen Sie einen etwas längeren Ausdruck:
[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)
Siehe pkeller Antwort für eine ausführlichere Erklärung dieses Musters
Wenn Sie nicht dezimale Zahlen wie Hex und Oktal einfügen möchten, lesen Sie meine Antwort auf Wie identifiziere ich, ob eine Zeichenfolge eine Zahl ist? .
Wenn Sie möchten bestätigen , dass eine Eingabe eine Zahl ( und nicht eine Zahl innerhalb des Eingangs zu finden), dann sollten Sie das Muster umgeben mit ^
und $
, etwa so:
^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$
Unregelmäßige reguläre Ausdrücke
"Reguläre Ausdrücke", wie sie in den meisten modernen Sprachen, APIs, Frameworks, Bibliotheken usw. implementiert sind, basieren auf einem in der formalen Sprachtheorie entwickelten Konzept . Softwareentwickler haben jedoch viele Erweiterungen hinzugefügt, die diese Implementierungen weit über die formale Definition hinausführen. Während sich die meisten Engines für reguläre Ausdrücke ähneln, gibt es eigentlich keinen Standard. Aus diesem Grund hängt vieles davon ab, welche Sprache, API, welches Framework oder welche Bibliothek Sie verwenden.
(Um Verwirrung zu vermeiden , haben viele übrigens " Regex " oder " Regexp " verwendet, um diese erweiterten Übereinstimmungssprachen zu beschreiben. Weitere Informationen finden Sie unter Ist ein Regex mit einem regulären Ausdruck identisch ? Auf RexEgg.com.)
Das heißt, die meisten Regex-Motoren (eigentlich alle, soweit ich weiß) würden akzeptieren \.
. Höchstwahrscheinlich gibt es ein Problem mit der Flucht.
Das Problem mit der Flucht
Einige Sprachen bieten integrierte Unterstützung für reguläre Ausdrücke, z. B. JavaScript . Für diejenigen Sprachen, die dies nicht tun, kann das Entkommen ein Problem sein.
Dies liegt daran, dass Sie grundsätzlich in einer Sprache innerhalb einer Sprache codieren. Java wird beispielsweise \
als Escape-Zeichen in seinen Zeichenfolgen verwendet. Wenn Sie also ein wörtliches Backslash-Zeichen in eine Zeichenfolge einfügen möchten, müssen Sie es maskieren:
// creates a single character string: "\"
String x = "\\";
Allerdings Regexes auch die Verwendung \
Charakter zu entkommen, wenn Sie also eine wörtliche übereinstimmen soll \
Charakter, müssen Sie es für die regexe Motor entweichen, und es dann wieder entkommen für Java:
// Creates a two-character string: "\\"
// When used as a regex pattern, will match a single character: "\"
String regexPattern = "\\\\";
In Ihrem Fall sind Sie dem Backslash-Zeichen in der Sprache, in der Sie programmieren, wahrscheinlich nicht entkommen:
// will most likely result in an "Illegal escape character" error
String wrongPattern = "\.";
// will result in the string "\."
String correctPattern = "\\.";
All diese Flucht kann sehr verwirrend werden. Wenn die Sprache, mit der Sie arbeiten, unformatierte Zeichenfolgen unterstützt , sollten Sie diese verwenden, um die Anzahl der Backslashes zu verringern, aber nicht alle Sprachen (insbesondere Java). Glücklicherweise gibt es eine Alternative, die manchmal funktioniert:
String correctPattern = "[.]";
Für eine Regex-Engine \.
und [.]
genau das Gleiche bedeuten. Beachten Sie, dass dies nicht in jedem Fall funktioniert, wie z. B. newline ( \\n
), offene eckige Klammer ( \\[
) und Backslash ( \\\\
oder [\\]
).
Ein Hinweis zu übereinstimmenden Zahlen
(Hinweis: Es ist schwieriger als Sie denken)
Das Abgleichen einer Zahl ist eines der Dinge, von denen Sie denken, dass sie mit Regex recht einfach sind, aber es ist tatsächlich ziemlich schwierig. Schauen wir uns Stück für Stück Ihren Ansatz an:
[-+]?
Passen Sie eine optionale -
oder+
[0-9]*
Entspricht 0 oder mehr aufeinander folgenden Ziffern
\.?
Passen Sie eine optionale .
[0-9]*
Entspricht 0 oder mehr aufeinander folgenden Ziffern
Erstens können wir diesen Ausdruck ein wenig bereinigen, indem wir eine Zeichenklassen-Kurzform für die Ziffern verwenden (beachten Sie, dass dies auch für das oben erwähnte Escape-Problem anfällig ist):
[0-9]
= \d
Ich werde \d
unten verwenden, aber denken Sie daran, dass es das gleiche bedeutet wie [0-9]
. (Nun, tatsächlich \d
stimmen in einigen Engines die Ziffern aller Skripte überein, sodass mehr als [0-9]
die Ziffern übereinstimmen , aber das ist in Ihrem Fall wahrscheinlich nicht von Bedeutung.)
Wenn Sie sich das genau ansehen, werden Sie feststellen, dass jeder einzelne Teil Ihres Musters optional ist . Dieses Muster kann mit einer Zeichenfolge mit einer Länge von 0 übereinstimmen. eine Zeichenfolge, die nur aus +
oder besteht -
; oder eine Zeichenfolge, die nur aus a besteht .
. Dies ist wahrscheinlich nicht das, was Sie beabsichtigt haben.
Um dies zu beheben, ist es hilfreich, zunächst Ihren regulären Ausdruck mit der minimal erforderlichen Zeichenfolge zu "verankern", wahrscheinlich mit einer einzelnen Ziffer:
\d+
Jetzt wollen wir den Dezimalteil hinzufügen, aber er geht nicht dahin, wo Sie denken, dass es sein könnte:
\d+\.?\d* /* This isn't quite correct. */
Dies entspricht weiterhin Werten wie 123.
. Schlimmer noch, es hat einen Hauch von Bösem . Der Zeitraum ist optional, dh Sie haben zwei wiederholte Klassen nebeneinander ( \d+
und \d*
). Dies kann tatsächlich gefährlich sein, wenn es falsch verwendet wird und Ihr System für DoS-Angriffe geöffnet wird.
Um dies zu beheben, müssen wir den Punkt nicht als optional behandeln, sondern nach Bedarf behandeln (um die wiederholten Zeichenklassen zu trennen) und stattdessen den gesamten Dezimalteil optional machen:
\d+(\.\d+)? /* Better. But... */
Das sieht jetzt besser aus. Wir benötigen einen Zeitraum zwischen der ersten und der zweiten Ziffernfolge, aber es gibt einen schwerwiegenden Fehler: Wir können nicht übereinstimmen, .123
da jetzt eine führende Ziffer erforderlich ist.
Dies ist eigentlich ziemlich einfach zu beheben. Anstatt den "dezimalen" Teil der Zahl optional zu machen, müssen wir ihn als eine Folge von Zeichen betrachten: 1 oder mehr Zahlen, denen ein Präfix vorangestellt werden .
kann, denen 0 oder mehr Zahlen vorangestellt werden können:
(\d*\.)?\d+
Jetzt fügen wir einfach das Zeichen hinzu:
[+-]?(\d*\.)?\d+
Natürlich sind diese Schrägstriche in Java ziemlich ärgerlich, daher können wir sie in unseren Langform-Zeichenklassen ersetzen:
[+-]?([0-9]*[.])?[0-9]+
Matching versus Validating
Dies ist in den Kommentaren ein paar Mal aufgetaucht, daher füge ich einen Nachtrag zum Matching versus Validieren hinzu.
Das Ziel des Matchings ist es, einen Inhalt innerhalb der Eingabe zu finden (die "Nadel im Heuhaufen"). Das Ziel der Validierung besteht darin, sicherzustellen, dass die Eingabe in einem erwarteten Format vorliegt.
Regexes stimmen naturgemäß nur mit Text überein . Bei einigen Eingaben finden sie entweder passenden Text oder nicht. Durch "Einrasten" eines Ausdrucks am Anfang und Ende der Eingabe mit Ankertags ( ^
und $
) können wir jedoch sicherstellen, dass keine Übereinstimmung gefunden wird, es sei denn, die gesamte Eingabe stimmt mit dem Ausdruck überein, wobei zur Validierung Regexes verwendet werden .
Der oben beschriebene reguläre Ausdruck ( [+-]?([0-9]*[.])?[0-9]+
) stimmt mit einer oder mehreren Zahlen innerhalb einer Zielzeichenfolge überein . Also gegeben die Eingabe:
apple 1.34 pear 7.98 version 1.2.3.4
Die Regex paßt auf 1.34
, 7.98
, 1.2
, .3
und .4
.
Um zu überprüfen, ob eine bestimmte Eingabe eine Zahl und nichts anderes als eine Zahl ist, "fangen" Sie den Ausdruck am Anfang und Ende der Eingabe, indem Sie ihn in Ankertags einschließen:
^[+-]?([0-9]*[.])?[0-9]+$
Dies findet nur dann eine Übereinstimmung, wenn die gesamte Eingabe eine Gleitkommazahl ist, und findet keine Übereinstimmung, wenn die Eingabe zusätzliche Zeichen enthält. Bei der Eingabe 1.2
wird also eine Übereinstimmung gefunden, es werden jedoch apple 1.2 pear
keine Übereinstimmungen gefunden.
Beachten Sie, dass einige regex Motoren haben eine validate
, isMatch
oder eine ähnliche Funktion, die im Wesentlichen das tut , was ich automatisch beschrieben habe, zurückkehrt , true
wenn eine Übereinstimmung gefunden wird und false
wenn keine Übereinstimmung gefunden wird. Beachten Sie auch, dass Sie mit einigen Engines Flags setzen können, die die Definition von ^
und ändern und $
mit dem Anfang / Ende einer Zeile und nicht mit dem Anfang / Ende der gesamten Eingabe übereinstimmen. Dies ist normalerweise nicht die Standardeinstellung, aber halten Sie Ausschau nach diesen Flags.