J'essaye de localiser et de remplacer tous les nombres dans un corps de texte. J'ai trouvé quelques exemples de regex, qui résolvent presque le problème, mais aucun n'est encore parfait. Le problème que j'ai est que les nombres dans mon texte peuvent ou non avoir des décimales et des virgules. Par exemple:
«Le renard de 5 000 lb a sauté par-dessus une clôture de 99 999 99998713 pieds.»
Le regex doit retourner " 5000
" et " 99,999.99998713
". Les exemples que j'ai trouvés séparent les nombres sur la virgule ou sont limités à deux décimales. Je commence à comprendre suffisamment les regex pour voir pourquoi certains exemples sont limités à deux décimales, mais je n'ai pas encore appris à le surmonter et à inclure également la virgule pour obtenir la séquence entière.
Voici ma dernière version:
[0-9]+(\.[0-9][0-9]?)?
Qui renvoie, " 5000
", " 99,99
", " 9.99
" et " 998713
" pour le texte ci-dessus.
.,.,.
ou9,9,9,9
ou9,9.99.9
. Ces expressions régulières n'exigeront pas que les nombres soient au format approprié et, au pire, traiteront la ponctuation comme des nombres. Il y a quelques ajustements facultatifs possibles (par exemple s'il faut autoriser les zéros de début et de fin), mais certaines des réponses que je vois sont carrément incorrectes. Je n'aime vraiment pas le vote négatif, en particulier sur les tentatives honnêtes, mais je pense que les réponses doivent être nettoyées. C'est une question courante et sera certainement posée à nouveau.Réponses:
EDIT: Étant donné que cela a suscité beaucoup de vues, permettez-moi de commencer par donner à tout le monde ce pour quoi ils ont cherché sur Google:
Maintenant que ce n'est plus le cas, la plupart des éléments suivants sont des commentaires sur la complexité des expressions rationnelles si vous essayez d'être intelligent avec elles, et pourquoi vous devriez chercher des alternatives. Lisez à vos risques et périls.
Ceci est une tâche très commune, mais toutes les réponses que je vois ici jusqu'à présent acceptera les entrées qui ne correspondent pas à votre format numérique, tels que
,111
,9,9,9
ou même.,,.
. C'est assez simple à corriger, même si les nombres sont incorporés dans un autre texte. À mon humble avis tout ce qui ne parvient pas à tirer 1,234.56 et 1234- et seuls les numéros -hors deabc22 1,234.56 9.9.9.9 def 1234
est une mauvaise réponse.Tout d'abord, si vous n'avez pas besoin de faire tout cela dans une seule regex, ne le faites pas. Une seule expression régulière pour deux formats de nombre différents est difficile à maintenir même s'ils ne sont pas incorporés dans un autre texte. Ce que vous devez vraiment faire est de diviser le tout sur des espaces, puis d'exécuter deux ou trois expressions rationnelles plus petites sur les résultats. Si ce n'est pas une option pour vous, continuez à lire.
Modèle de base
Compte tenu des exemples que vous avez donnés, voici une expression régulière simple qui autorise à peu près n'importe quel
0000
format entier ou décimal et bloque tout le reste:En voici un qui nécessite un
0,000
format:Mettez-les ensemble, et les virgules deviennent facultatives tant qu'elles sont cohérentes:
Numéros intégrés
Les modèles ci-dessus nécessitent que l'entrée entière soit un nombre. Vous recherchez des nombres incorporés dans du texte, vous devez donc desserrer cette partie. D'un autre côté, vous ne voulez pas qu'il voie
catch22
et pense qu'il a trouvé le numéro 22. Si vous utilisez quelque chose avec le support lookbehind (comme .NET), c'est assez simple: remplacez^
par(?<!\S)
et$
par(?!\S)
et vous êtes bon aller:Si vous travaillez avec JavaScript ou Ruby ou quelque chose du genre, les choses commencent à paraître plus complexes:
Vous devrez utiliser des groupes de capture; Je ne peux pas penser à une alternative sans regarder derrière l'assistance. Les numéros que vous voulez seront dans le groupe 1 (en supposant que tout le match est le groupe 0).
Validation et règles plus complexes
Je pense que cela couvre votre question, donc si c'est tout ce dont vous avez besoin, arrêtez de lire maintenant. Si vous voulez devenir plus sophistiqué, les choses se compliquent très rapidement. Selon votre situation, vous souhaiterez peut-être bloquer tout ou partie des éléments suivants:
Juste pour le plaisir, supposons que vous vouliez bloquer les 3 premiers, mais autorisez le dernier. Que devrais tu faire? Je vais vous dire ce que vous devez faire, vous devez utiliser une regex différente pour chaque règle et affiner progressivement vos correspondances. Mais pour relever le défi, voici comment faire tout cela en un seul modèle géant:
Et voici ce que cela signifie:
Testé ici: http://rextester.com/YPG96786
Cela permettra des choses comme:
Cela bloquera des choses comme:
Il y a plusieurs façons de rendre cette expression régulière plus simple et plus courte, mais comprenez que changer le modèle détendra ce qu'il considère comme un nombre.
Étant donné que de nombreux moteurs de regex (par exemple JavaScript et Ruby) ne prennent pas en charge la recherche négative, la seule façon de le faire correctement est d'utiliser des groupes de capture:
Les numéros que vous recherchez seront dans le groupe de capture 1.
Testé ici: http://rubular.com/r/3HCSkndzhT
Une dernière note
De toute évidence, c'est une regex massive, compliquée et presque illisible. J'ai apprécié le défi, mais vous devriez vous demander si vous voulez vraiment l'utiliser dans un environnement de production. Au lieu d'essayer de tout faire en une seule étape, vous pouvez le faire en deux: une expression régulière pour attraper tout ce qui pourrait être un nombre, puis une autre pour éliminer tout ce qui n'est pas un nombre. Ou vous pouvez effectuer un traitement de base, puis utiliser les fonctions d'analyse numérique intégrées de votre langage. Votre choix.
la source
Il y a quelques jours, j'ai travaillé sur le problème de la suppression des zéros de fin de la chaîne d'un nombre .
Dans la continuité de ce problème, je trouve celui-ci intéressant car il élargit le problème aux nombres comportant des virgules.
J'ai pris le modèle de regex que j'avais écrit dans ce problème précédent sur lequel j'ai travaillé et je l'ai amélioré afin qu'il puisse traiter les nombres avec des virgules comme une réponse à ce problème.
J'ai été emporté par mon enthousiasme et mon goût pour les expressions régulières. Je ne sais pas si le résultat correspond exactement au besoin exprimé par Michael Prescott. Je serais intéressé de connaître les points qui sont en excès ou en manque dans mon regex, et de le corriger pour le rendre plus approprié pour vous.
Maintenant, après une longue session de travail sur cette regex, j'ai une sorte de poids dans le cerveau, donc je ne suis pas assez frais pour donner beaucoup d'explications. Si les points sont obscurs et si quelqu'un peut être suffisamment intéressé, n'hésitez pas à me le demander.
La regex est construite de manière à pouvoir détecter les nombres exprimés en notation scientifique 2E10 ou même 5,22,454.12E-00.0478 , supprimant également les zéros inutiles dans les deux parties de ces nombres. Si un exposant est égal à zéro, le nombre est modifié pour qu'il n'y ait plus d'exposant.
J'ai mis un peu de vérification dans le modèle pour que certains cas particuliers ne correspondent pas, par exemple « 12 ..57» ne correspond pas. Mais dans ', 111' la chaîne '111' correspond parce que la virgule précédente est considérée comme une virgule non pas dans un nombre mais une virgule de phrase.
Je pense que la gestion des virgules devrait être améliorée, car il me semble qu'il n'y a que 2 chiffres entre les virgules dans la numérotation indienne. Ce ne sera pas difficile à corriger, je présume
Voici un code illustrant le fonctionnement de mon regex. Il y a deux fonctions, selon que l'on veut que les nombres '.1245' soient transformés en '0.1245' ou non. Je ne serais pas surpris si des erreurs ou des correspondances ou des non-concordances indésirables subsisteraient pour certains cas de chaînes de nombres; alors j'aimerais connaître ces cas pour comprendre et corriger la carence.
Je m'excuse pour ce code écrit en Python, mais les regex sont trans-langage et je pense que tout le monde sera capable de comprendre le modèle du reex
résultat
la source
L'expression régulière ci-dessous correspondra aux deux nombres de votre exemple.
Il renverra 5000 et 99 999,99998713 - correspondant à vos besoins.
la source
this,that
.\b\d[\d,.]+\b
9....9
ou1,,,,X
(bien que le X ne soit pas inclus dans le match).\b\d[\d,.]*\b
est suffisamment proche pour que si vous modifiez votre réponse, je supprime le -1. Cela devrait être un * au lieu d'un + cependant;\b\d[\d,.]+\b
n'autorisera pas les nombres à un chiffre.Prenant une certaine liberté avec les exigences, vous recherchez
Mais notez que cela correspondra par exemple 11,11,1
la source
\d+([\d,]?\d)*(\.\d+)?
lieu de\d+(,\d+)*(\.\d+)?
? Je pense qu'ils donneraient des correspondances équivalentes, même si les groupes de capture seraient différents.Cela suppose qu'il y a toujours au moins un chiffre avant ou après une virgule ou une décimale et suppose également qu'il y a au plus une décimale et que toutes les virgules précèdent la virgule.
la source
999999,9,9,9,9
.(,\d+)
en(,\d\d\d)
je suppose.Cette expression régulière:
Correspond à chaque nombre de la chaîne:
1 1,0 0,1 1,001 1,000 1,000,000 1000,1 1,000,1 1,323,444,000 1,999 1,222,455,666,0 1,244
la source
Voici une regex:
qui accepte les nombres:
123456789
,123.123
123 456 789
,123 456 789.100
,123,456
,3,232,300,000.00
Tests: http://regexr.com/3h1a2
la source
Voici une autre construction qui commence par le format numérique le plus simple puis, de manière non superposée, ajoute progressivement des formats numériques plus complexes:
Regep Java:
En tant que chaîne Java (notez que le \ nécessaire pour échapper à \ et. Puisque \ et. Ont une signification particulière dans une expression rationnelle lorsqu'ils sont seuls):
Explication:
Cette expression rationnelle a la forme A | B | C | D | E | F où A, B, C, D, E, F sont elles-mêmes des expressions rationnelles qui ne se chevauchent pas. En général, je trouve plus facile de commencer avec les correspondances les plus simples possibles, A. Si A manque les correspondances que vous voulez, créez un B qui est une modification mineure de A et comprend un peu plus de ce que vous voulez. Ensuite, sur la base de B, créez un C qui attrape plus, etc. il est plus facile de comprendre une expression rationnelle avec 20 expressions rationnelles simples sans chevauchement connectées avec des OR plutôt que quelques expressions rationnelles avec des correspondances plus complexes. Mais, chacun à lui!
A est (\ d) et correspond exactement à l'un des 0,1,2,3,4,5,6,7,8,9, ce qui ne peut pas être plus simple!
B est ([1-9] \ d +) et ne correspond qu'aux nombres de 2 chiffres ou plus, le premier excluant 0. B correspond exactement à l'un des 10,11,12, ... B ne chevauche pas A mais est une petite modification de A.
C est (. \ D +) et correspond uniquement à une décimale suivie d'un ou plusieurs chiffres. C correspond exactement à l'un des .0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .00 .01 .02 .... .23000 ... C autorise les éros à droite ce que je préfère: s'il s'agit de données de mesure, le nombre de zéros de fin indique le niveau de précision. Si vous ne voulez pas les zéros de fin à droite, remplacez (. \ D +) par (. \ D * [1-9]) mais cela exclut également .0 qui, je pense, devrait être autorisé. C est également une petite modification de A.
D est (\ d. \ D *) qui est A plus les décimales avec des zéros à droite. D ne correspond qu'à un seul chiffre, suivi d'une décimale, suivi de zéro ou plusieurs chiffres. D correspond à 0. 0,0 0,1 0,2 .... 0,01000 ... 9. 9.0 9.1..0.0230000 .... 9.9999999999 ... Si vous souhaitez exclure "0." puis changez D en (\ d. \ d +). Si vous voulez exclure les zéros de fin à droite, changez D en (\ d. \ D * [1-9]) mais cela exclut 2.0 qui, je pense, devrait être inclus. D ne chevauche pas A, B ou C.
E est ([1-9] \ d +. \ D *) qui est B plus les décimales avec des zéros à droite. Si vous souhaitez exclure "13.", par exemple, remplacez E par ([1-9] \ d +. \ D +). E ne chevauche pas A, B, C ou D. E correspond à 10. 10.0 10.0100 .... 99.9999999999 ... Les zéros de fin peuvent être traités comme dans 4. et 5.
F est ([1-9] \ d {0,2} (, \ d {3}) + (. \ D *)?) Et ne fait correspondre que les nombres avec des virgules et éventuellement des décimales autorisant les zéros de fin à droite. Le premier groupe ([1-9] \ d {0,2}) correspond à un chiffre différent de zéro suivi de zéro, un ou deux chiffres supplémentaires. Le deuxième groupe (, \ d {3}) + correspond à un groupe de 4 caractères (une virgule suivie d'exactement trois chiffres) et ce groupe peut correspondre une ou plusieurs fois (pas de correspondance signifie pas de virgule!). Enfin, (. \ D *)? ne correspond à rien ou correspond. par lui-même, ou correspond à une décimale. suivi d'un nombre quelconque de chiffres, éventuellement aucun. Encore une fois, pour exclure des éléments tels que «1,111.», Remplacez (. \ D *) par (. \ D +). Les zéros de fin peuvent être traités comme en 4. ou 5. F ne chevauche pas A, B, C, D ou E. Je ne pourrais pas penser à une expression rationnelle plus facile pour F.
Faites-moi savoir si vous êtes intéressé et je peux modifier ci-dessus pour gérer les zéros de fin à droite comme vous le souhaitez.
Voici ce qui correspond à l'expression rationnelle et ce qui ne fonctionne pas:
la source
\ b -------> limite de mot
\ d + ------> un ou chiffre
, --------> contenant des virgules,
Par exemple:
sddsgg 70 000 sdsfdsf fdgfdg70,00
sfsfsd 5,44,4343 5,7788,44 555
Il correspondra:
70,
5,
44,
, 44
la source
Cela correspondrait à n'importe quel petit ou grand nombre comme suit avec ou sans virgule
ou
la source