TL; DR
Utilisez [.]
au lieu de \.
et [0-9]
au lieu de \d
pour éviter les problèmes d'échappement dans certains langages (comme Java).
Merci à celui sans nom pour avoir reconnu cela à l'origine.
Un modèle relativement simple pour faire correspondre un nombre à virgule flottante est
[+-]?([0-9]*[.])?[0-9]+
Cela correspondra:
Voir un exemple de travail
Si vous souhaitez également faire correspondre 123.
(un point sans partie décimale), vous aurez besoin d'une expression légèrement plus longue:
[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)
Voir la réponse de pkeller pour une explication plus complète de ce modèle
Si vous souhaitez inclure des nombres non décimaux, tels que hexadécimal et octal, consultez ma réponse à Comment puis-je identifier si une chaîne est un nombre? .
Si vous voulez valider qu'une entrée est un nombre (plutôt que de trouver un nombre dans l'entrée), vous devez entourer le motif avec ^
et $
, comme ceci:
^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$
Expressions régulières irrégulières
Les «expressions régulières», telles qu'implémentées dans la plupart des langages modernes, API, frameworks, bibliothèques, etc., sont basées sur un concept développé dans la théorie formelle du langage . Cependant, les ingénieurs logiciels ont ajouté de nombreuses extensions qui poussent ces implémentations bien au-delà de la définition formelle. Ainsi, alors que la plupart des moteurs d'expressions régulières se ressemblent, il n'y a en fait pas de norme. Pour cette raison, tout dépend du langage, de l'API, du framework ou de la bibliothèque que vous utilisez.
(Incidemment, pour aider à réduire la confusion, beaucoup ont commencé à utiliser « regex » ou « regexp » pour décrire ces langages de correspondance améliorés. Voir Une expression régulière est-elle identique à une expression régulière? Sur RexEgg.com pour plus d'informations.)
Cela dit, la plupart des moteurs de regex (en fait, tous, pour autant que je sache) accepteraient \.
. Très probablement, il y a un problème avec l'échappement.
Le problème de la fuite
Certains langages ont un support intégré pour les expressions régulières, comme JavaScript . Pour les langues qui ne le font pas, s'échapper peut être un problème.
C'est parce que vous codez essentiellement dans une langue au sein d'une langue. Java, par exemple, utilise \
comme caractère d'échappement dans ses chaînes, donc si vous voulez placer un caractère anti-slash littéral dans une chaîne, vous devez l'échapper:
// creates a single character string: "\"
String x = "\\";
Cependant, les expressions régulières utilisent également le \
caractère pour s'échapper, donc si vous voulez faire correspondre un \
caractère littéral , vous devez l'échapper pour le moteur d'expression régulière, puis l'échapper à nouveau pour Java:
// Creates a two-character string: "\\"
// When used as a regex pattern, will match a single character: "\"
String regexPattern = "\\\\";
Dans votre cas, vous n'avez probablement pas échappé à la barre oblique inverse dans le langage dans lequel vous programmez:
// will most likely result in an "Illegal escape character" error
String wrongPattern = "\.";
// will result in the string "\."
String correctPattern = "\\.";
Toutes ces évasions peuvent devenir très déroutantes. Si le langage avec lequel vous travaillez prend en charge les chaînes brutes , vous devez les utiliser pour réduire le nombre de barres obliques inverses, mais tous les langages ne le font pas (notamment Java). Heureusement, il existe une alternative qui fonctionnera parfois:
String correctPattern = "[.]";
Pour un moteur regex, \.
et cela [.]
signifie exactement la même chose. Notez que cela ne fonctionne pas dans tous les cas, comme newline ( \\n
), open square bracket ( \\[
) et backslash ( \\\\
ou [\\]
).
Remarque sur la correspondance des nombres
(Indice: c'est plus difficile que vous ne le pensez)
Faire correspondre un nombre est une de ces choses que vous pensez être assez facile avec regex, mais c'est en fait assez délicat. Jetons un coup d'œil à votre approche, pièce par pièce:
[-+]?
Faites correspondre une option -
ou+
[0-9]*
Correspond à 0 ou plusieurs chiffres séquentiels
\.?
Faites correspondre une option .
[0-9]*
Correspond à 0 ou plusieurs chiffres séquentiels
Tout d'abord, nous pouvons nettoyer un peu cette expression en utilisant un raccourci de classe de caractères pour les chiffres (notez que cela est également sensible au problème d'échappement mentionné ci-dessus):
[0-9]
= \d
Je vais utiliser \d
ci-dessous, mais gardez à l'esprit que cela signifie la même chose que [0-9]
. (Eh bien, en fait, dans certains moteurs \d
, les chiffres de tous les scripts correspondront, donc cela correspondra plus que ce [0-9]
ne sera, mais ce n'est probablement pas significatif dans votre cas.)
Maintenant, si vous regardez cela attentivement, vous vous rendrez compte que chaque partie de votre modèle est facultative . Ce modèle peut correspondre à une chaîne de longueur 0; une chaîne composée uniquement de +
ou -
; ou, une chaîne composée uniquement de a .
. Ce n'est probablement pas ce que vous vouliez.
Pour résoudre ce problème, il est utile de commencer par «ancrer» votre expression régulière avec la chaîne requise le plus strict, probablement un seul chiffre:
\d+
Maintenant, nous voulons ajouter la partie décimale, mais elle ne va pas là où vous pensez qu'elle pourrait:
\d+\.?\d* /* This isn't quite correct. */
Cela correspondra toujours à des valeurs telles que 123.
. Pire encore, il y a une teinte perverse à ce sujet. Le point est facultatif, ce qui signifie que vous avez deux classes répétées côte à côte ( \d+
et \d*
). Cela peut en fait être dangereux s'il est utilisé de la mauvaise manière, ouvrant votre système aux attaques DoS.
Pour résoudre ce problème, plutôt que de traiter le point comme facultatif, nous devons le traiter comme requis (pour séparer les classes de caractères répétées) et à la place rendre la partie décimale entière facultative:
\d+(\.\d+)? /* Better. But... */
Cela va mieux maintenant. Nous avons besoin d'un point entre la première séquence de chiffres et la seconde, mais il y a un défaut fatal: nous ne pouvons pas faire correspondre .123
car un chiffre de tête est maintenant requis.
C'est en fait assez facile à résoudre. Au lieu de rendre la partie "décimale" du nombre facultative, nous devons la considérer comme une séquence de caractères: 1 ou plusieurs nombres qui peuvent être préfixés par un .
qui peuvent être préfixés par 0 ou plusieurs nombres:
(\d*\.)?\d+
Maintenant, nous ajoutons simplement le signe:
[+-]?(\d*\.)?\d+
Bien sûr, ces barres obliques sont assez ennuyeuses en Java, nous pouvons donc les remplacer dans nos classes de caractères de forme longue:
[+-]?([0-9]*[.])?[0-9]+
Matching versus validation
Cela a été mentionné dans les commentaires à quelques reprises, alors j'ajoute un addendum sur l'appariement et la validation.
Le but de la correspondance est de trouver du contenu dans l'entrée ("l'aiguille dans une botte de foin"). Le but de la validation est de s'assurer que l'entrée est dans un format attendu.
Les expressions régulières, de par leur nature, ne correspondent qu'à du texte. Compte tenu de certains commentaires, ils trouveront un texte correspondant ou ils ne le trouveront pas. Cependant, en "accrochant" une expression au début et à la fin de l'entrée avec des balises d'ancrage ( ^
et $
), nous pouvons nous assurer qu'aucune correspondance n'est trouvée à moins que l'entrée entière ne corresponde à l'expression, en utilisant efficacement des expressions régulières pour valider .
Le regex décrit ci-dessus ( [+-]?([0-9]*[.])?[0-9]+
) correspondra à un ou plusieurs nombres dans une chaîne cible. Donc, compte tenu de l'entrée:
apple 1.34 pear 7.98 version 1.2.3.4
Le regex correspondra 1.34
, 7.98
, 1.2
, .3
et .4
.
Pour valider qu'une entrée donnée est un nombre et rien d'autre qu'un nombre, «accrochez» l'expression au début et à la fin de l'entrée en l'enveloppant dans des balises d'ancrage:
^[+-]?([0-9]*[.])?[0-9]+$
Cela ne trouvera une correspondance que si l'entrée entière est un nombre à virgule flottante, et ne trouvera pas de correspondance si l'entrée contient des caractères supplémentaires. Donc, étant donné l'entrée 1.2
, une correspondance sera trouvée, mais apple 1.2 pear
aucune correspondance ne sera trouvée.
Notez que certains moteurs regex ont une fonction validate
, isMatch
ou similaire, qui fait essentiellement ce que j'ai décrit automatiquement, retournant true
si une correspondance est trouvée et false
si aucune correspondance n'est trouvée. Gardez également à l'esprit que certains moteurs vous permettent de définir des indicateurs qui modifient la définition de ^
et $
, correspondant au début / à la fin d'une ligne plutôt qu'au début / à la fin de l'entrée entière. Ce n'est généralement pas la valeur par défaut, mais soyez à l'affût de ces drapeaux.