2010-08-23 7 views
6

Je suis un débutant dans les expressions régulières, j'apprécierais donc un peu de commentaires de nos pairs sur celui-ci. Il sera très utilisé sur mon site, donc tous les cas de bords bizarres peuvent totalement faire des ravages. L'idée est de saisir une quantité d'un ingrédient dans une recette en unités entières ou en fractions. En raison de mon mécanisme d'auto-complétion, juste un nombre est valide aussi (puisqu'il fera apparaître une liste déroulante). Ces lignes sont valables:Un moyen d'améliorer cette expression régulière?

1 
1/2 
1 1/2 
4 cups 
4 1/2 cups 
10 3/4 cups sliced 

La partie numérique de la ligne doit être son propre groupe, je peux analyser avec mon analyseur de fraction. Tout après la partie numérique devrait être un deuxième groupe. Au début, j'ai essayé ceci:

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

Ce presque fonctionne, mais "1 1/2 tasse" va s'analysable comme (1) (1/2 tasse) au lieu de (1 1/2) et (tasses). Après m'être gratté un peu la tête, j'ai déterminé que c'était à cause de la commande de ma clause «OU». (1) satisfait le \ d + et (. *) Satisfait le reste. J'ai donc changé cela:

^\s*(\d+\/\d+|\d+\s*\d+\/\d+|\d+)\s*([a-z].*)$ 

Cela fonctionne presque, mais permet bizarreries telles que « 1 1/2/4 tasses » ou « 1/2 3 tasses ». Je décide donc d'appliquer une lettre que le premier caractère après une expression numérique valide:

^\s*(\d+\/\d+|\d+\s*\d+\/\d+|\d+)\s*($|[a-z].*)$ 

Remarque Je suis en ce en mode insensible à la casse. Voici mes questions:

  1. L'expression peut-elle être améliorée? Je n'aime pas du tout la liste "OU" pour le nombre, la fraction, la fraction composée mais je ne pouvais pas penser à un moyen d'autoriser des nombres entiers, des fractions ou des fractions composées.

  2. Ce serait très bien si je pouvais retourner un groupe pour chaque mot après le composant numérique. Comme un groupe pour (10 3/4), un groupe pour (tasses) et un groupe pour (tranché). Il peut y avoir n'importe quel nombre de mots après. Est-ce possible?

Merci!

+0

Oh oups, manqué encore un cas .. La quantité peut être exprimée en décimal. J'ai donc ajouté une clause OU: ^ \ s * (\ d + \/\ d + | \ d + \ s * \ d + \/\ d + | \ d + | \ d * \. \ D) \ s * ($ | [az]. *) $ –

Répondre

3

Eh bien, il me semble que vous n'avez pas besoin de conditions OR du tout (mais voir ci-dessous).

Pour le bit numérique, vous pourriez vous en sortir avec:

\d+(\s+\d+/\d+) 

qui traiterait toutes ces valeurs fractionnaires. Je garderais toujours votre séparateur décimal séparé par une clause OR car cela compliquerait probablement les choses. Donc, je pense que vous pourriez probablement vous en sortir avec quelque chose comme:

^\s*((\d+\s)?(\d+/\d+)?|\d+(\.\d+)?)\s*([a-z].*)?$ 
| |     |   | | 
| |     |   | +--- start of alpha section. 
| |     |   +------ optional white space. 
| |     +------------------ decimal (nn[.nn]) 
| +------------------------------------- fractional ([nn ][nn/nn]) 
+----------------------------------------- optional starting space. 

bien qui permet une quantité fractionnelle vide de sorte que vous pouvez être mieux avec ce que vous avez (entier, fractionnaire et décimale dans des clauses distinctes OR) .

Je préfère le ([a-z].*)?$ construit pour me ($|[a-z].*)$ mais peut-être juste une aversion sur mon passé pour avoir plusieurs marqueurs de fin de ligne dans mon RE :-)


Mais, en toute honnêteté, je pense que vous peut-être essayer d'écraser une mouche avec une ogive thermo-nucléaire ici.

Avez-vous vraiment besoin de restreindre ce qui est entré. J'ai vu des recettes qui appellent a pinch of salt et a handful of sultanas. Personnellement, je pense que vous pouvez être restrictive dans ce que vous autorisez. J'aurais un champ de forme libre pour la quantité et un menu déroulant pour le type de nourriture (en fait je laisserais probablement juste la forme libre pour le lot à moins que j'offrais la capacité de rechercher des recettes basées sur ce qui est dans le réfrigérateur).

+0

Peut-être que nous utilisons des analyseurs différents, mais cela ne correspond à aucun de mes exemples ci-dessus .. Mais je pense que je vois ce que vous essayez de faire avec le point d'interrogation .. –

+0

@Mike, je ne suis pas aussi au courant avec le moteur Javascript RE que je le voudrais, mais j'avais espéré que les bits descriptifs étaient en train de traverser l'idée. – paxdiablo

+0

Yup, en regardant votre expression, je pense que cela devrait fonctionner aussi, mais pour une raison quelconque, il ne fonctionne pas :) J'utilise RegExTester.com pour tester les choses. –

1

Je crois que ce regex devrait faire ce que vous voulez:

/^\s*(\d+ \d+\/\d+|\d+\/\d+|\d+)\s*(.*)/ 

Pour correspondre les mots spécifiques que vous devez simplement faire une scission sur les espaces après l'analyse syntaxique. Il y a quelque chose que vous ne voulez pas faire avec regexes;)

+0

Yup qui fonctionne, seulement pas de support décimal .. et j'ai changé (. *) À ([az]. *) Pour se débarrasser de choses comme 1/2/tasses .. –

+0

En fait probablement ($ | [az]. *) est encore mieux, puisque je ne veux rien exiger après la partie numérique. –

+0

Ah oui. Si vous voulez un support décimal, utilisez plutôt [\ d.] + '. Il est difficile de le conserver complètement dans une regex si vous voulez ajouter des règles complexes. – Wolph

Questions connexes