2009-08-14 6 views
1

Je ne peux pas pour la vie de moi comprendre pourquoi l'expression rationnelle suivante ne peut pas correspondre à 4 flotteurs. Il y a quelques règles pour la façon dont les flottants peuvent être écrits.RegEx correspondant 4 flotteurs

  • le flotteur varie de 0 à 1
  • vous pouvez sauter le premier chiffre 0 si son
  • il y a un nombre illimité de chiffres après la période.

Theese sont valides flotteurs

  • 1,0
  • 0,0
  • .0
  • 0,123
  • .123

Maintenant, pour le code que j'ai essayé entre autres

string input = " 0 0 0 .4"; 
string regex = @"[0-1]*(\.[0-9]*)*\s[0-1]*(\.[0-9]*)*\s[0-1]*(\.[0-9]*)*\s[0-1]*(\.[0-9]*)*"; 
Regex r = new Regex(regex, RegexOptions.Compiled); 
Match m = r.Match(input); 

m.Value Returns "0 0 0" où je pense à revenir "0 0 0 0,4"

J'ai essayé

[0-1]{0,1}(\.[0-9]*)*\s[0-1]{0,1}(\.[0-9]*)*\s[0-1]{0,1}(\.[0-9]*)*\s[0-1]{0,1}(\.[0-9]*)* 

aswell mais il semble que .net ne pas faire face bien avec la syntaxe {0,1} (ou je suis juste en utilisant mal)

J'ai essayé de regarder http://www.regular-expressions.info/reference.html et {0 , 1} devrait être valide à ma compréhension au moins.

j'ai réussi à faire une regex qui correspond à la chaîne dans le petit outil matcher regex je à ma disposition, mais regex ne fonctionnait pas avec le .net classe Regex

MISE À JOUR

I J'utilise la regex conjointement avec un Tokenizer pour analyser un document plus volumineux.

Combineing ce que Pavel Minaev et psasik écrit le regex suivant fait une correspondance attendue

([0,1]|([0,1]?\.[0-9]+))\s([0,1]|([0,1]?\.[0-9]+))\s([0,1]|([0,1]?\.[0-9]+))\s([0,1]|([0,1]?\.[0-9]+)) 

Ce qui suit correspond au flotteur réelle

([0,1]|([0,1]?\.[0-9]+)) 
+0

([0,1] | ([0,1]? [0-9] +)) mais cela correspond aussi à des flottants supérieurs à 1 comme 1.23. BTW. vous devriez utiliser (?:) pour grouper au lieu de just() si vous n'avez pas besoin de références arrières. – arsenbonbon

+0

Je n'ai pas vraiment fait grand chose avec regex. Pourriez-vous nous en dire un peu plus à ce sujet? – thmsn

+0

Lorsque vous créez des parenthèses, le moteur regex mémorise la chaîne qui s'y trouve en cas de correspondance pour une utilisation ultérieure, soit dans l'expression elle-même, soit dans la chaîne de remplacement. Ceci est appelé backreferences. Si vous n'en avez pas besoin, vous pouvez l'éviter en utilisant simplement (?:) Au lieu de(). Ce n'est pas un gros problème, mais l'expression est plus rapide alors. Plus d'informations ici: http://www.regular-expressions.info/brackets.html En ce qui concerne la question de la gamme de valeur float jeter un oeil à ma réponse ci-dessous. – arsenbonbon

Répondre

4

Pour commencer, votre regex est mal en général - En raison de l'utilisation excessive de *, il se fera un plaisir de trouver quelque chose comme 10101.10101.10101.

La raison de votre résultat particulier est que votre chaîne d'entrée commence par un espace " ".Ainsi, le match va comme ceci:

  • premiers [0-1]* matchs chaîne vide au début
  • premiers (\.[0-9]*)* matchs chaîne vide « après » cette chaîne vide
  • premier \s correspond au caractère de l'espace de départ dans l'entrée
  • deuxième [0-1]* matchs la première 0 dans l'entrée ...
  • troisième \s correspond à la troisième espace dans l'entrée (celle qui précède le troisième 0)

Aucun groupe correspondent en fait quoi que ce soit (ou plutôt ils toutes les sélections des chaînes vides, parce que vous utilisez *).

+0

Pourriez-vous expliquer plus en détail pourquoi ils correspondent à ce que vous avez écrit? Je pensais * ment 0 ou plusieurs correspondances – thmsn

+0

Oui, et "0 correspond" correspondra, bien évidemment, à une chaîne vide. Il doit être d'accord avec cet espace au tout début, et la première chose qui correspond à votre regex est '\ s'. Donc, il essaye de faire correspondre tout ce qui précède '\ s', et puisque vous utilisez' * 'partout, il le fait correspondre à la chaîne vide" précédent "l'espace. –

1
float [0-1]|([0-1]?\.[0-9]+) 
ws [ \t] 

{ws}*{float}{ws}+{float}{ws}+{float}{ws}+{float}{ws}* 
+1

a fini par utiliser ([0,1] | ([0,1]? \. [0-9] +)) \ s ([0,1] | ([0,1]? \. [0-9] +)) \ s ([0,1] | ([0,1]? \. [0-9] +)) \ s ([0, 1] | ([0,1]? \. [0-9] +)) et obtenir une correspondance réussie :) – thmsn

+0

Cool. Je pensais que je ferais un peu plus facile à lire/maintenir pour vous, peut-être que vous voulez des espaces variables. – DevDevDev

0

Je ne sais pas C#, mais l'expression rationnelle suivante devrait répondre à vos besoins:

(?:(?<=\s)\.\d+|0\.\d+|[01]|1\.0)(?=\s|$) 

Edit: Oh, et si vous voulez vérifier s'il y a exactement 4 flotteurs dans la chaîne, il serait comme ceci:

(?:(?:(?<=\s)\.\d+|0\.\d+|[01]|1\.0)(?:\s|$)){4} 

Une petite explication sur l'expression:

le groupe extérieur (?) est juste pour répéter la chose 4 fois. Le premier groupe interne est ce qui correspond réellement aux flotteurs. Il y a quatre cas:

  • (?<=\s)\.\d+ Ceci correspond à un point suivi d'au moins un chiffre s'il est précédé d'un espace. Correspond à .123, .1 etc. Le (?<=\s) est un positive lookbehind. La différence entre un simple \s et est que dans le second cas, l'espace blanc ne fait pas partie de la correspondance
  • 0\.\d+ Ceci correspond à un zéro suivi d'un point suivi d'au moins un chiffre, par ex. 0,1, 0,123, 0,88
  • [01] Ceci correspond à 0 ou 1
  • 1\.0 La dernière possibilité, qui est de 1,0 et en fonction de vos exigences de la limite supérieure du flotteur

Le second correspond à un groupe interne, soit un espace; ou une nouvelle ligne. Donc, en anglais, l'expression signifie «match un du premier groupe suivi d'un du deuxième groupe répété quatre fois».

1

Essayez celui-ci:

[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)? 

De cette grande page: Regex Float Example

0

J'utiliser

(?:0(?:\.\d+)?|1(?:\.0+)?|\.\d+)(?:\s+(?:0(?:\.\d+)?|1(?:\.0+)?|\.\d+)){3} 

Le regex pour un seul numéro étant

0(?:\.\d+)?|1(?:\.0+)?|\.\d+ 

qui matches:

  • un zéro, éventuellement suivie d'une virgule décimale et un ou plusieurs chiffres, ou

  • un, éventuellement suivie d'une virgule décimale et un ou plusieurs zéros, ou

  • un point décimal suivi d'un ou plusieurs chiffres.

Ce n'est pas aussi compact que votre dernier noyau regex, ([01]|([01]?\.[0-9]+)), mais il est beaucoup plus claire, à la fois au moteur de regex et au lecteur humain. Si vous devez capturer les nombres individuellement, vous devrez vous débarrasser du quantificateur {3} et épeler le tout. Ne pas avoir peur de diviser un regex en de multiples lignes pour une meilleure lisibilité:

string regex = @"(0(?:\.\d+)?|1(?:\.0+)?|\.\d+)\s+" 
      + @"(0(?:\.\d+)?|1(?:\.0+)?|\.\d+)\s+" 
      + @"(0(?:\.\d+)?|1(?:\.0+)?|\.\d+)\s+" 
      + @"(0(?:\.\d+)?|1(?:\.0+)?|\.\d+)"; 

EDIT: Je ne parle pas C#, mais je viens de lire que les chaînes verbatim peuvent couvrir plusieurs lignes. Cela signifie que vous pouvez également profiter du mode sans espacement:

string regex = @"(?x) 
       (0(?:\.\d+)?|1(?:\.0+)?|\.\d+)\s+ 
       (0(?:\.\d+)?|1(?:\.0+)?|\.\d+)\s+ 
       (0(?:\.\d+)?|1(?:\.0+)?|\.\d+)\s+ 
       (0(?:\.\d+)?|1(?:\.0+)?|\.\d+) 
       "; 

Ou, au lieu d'utiliser le modificateur en ligne, (?x), vous pouvez passer le drapeau approprié au constructeur:

Regex r = new Regex(regex, RegexOptions.IgnorePatternWhitespace); 

De toute façon , le compilateur regex ignore tous les espaces dans la chaîne.

0

Peut-être que? (\d|.\d+|\d.\d+)\s+(\d|.\d+|\d.\d+)\s+(\d|.\d+|\d.\d+)\s+(\d|.\d+|\d.\d+)

0

Cette capture exactement un flotteur qui adhère à vos règles:

/^(\d?\.?\d+)$/ 

Cette capture des choses comme "12.1", à savoir flotteurs> 1:

/^(\d*\.?\d+)$/ 

depuis le REGEXP si court, je voudrais simplement le copier quatre fois et mettre \s+ entre les parenthèses de capture:

/^(\d*\.?\d+)\s+(\d*\.?\d+)\s+(\d*\.?\d+)\s+(\d*\.?\d+)$/ 

Si vous pouvez utiliser PCRE et souhaitez réduire l'expression:

/^(?:(\d*\.?\d+)\s+){3}(\d*\.?\d+)$/ 

Vérifiez si la capture entre parenthèses sont interpolés, cependant. Cela dépend du dialecte Regexp de votre langue.

+0

Oh, j'ai oublié les valeurs négatives! Avez-vous besoin d'eux? – polemon

Questions connexes