2010-08-23 18 views
6

Sono un principiante alle espressioni regolari, quindi apprezzerei un po 'di feedback tra pari su questo. Sarà pesantemente utilizzato sul mio sito, quindi qualsiasi caso limite strano può totalmente devastare. L'idea è di digitare una quantità di un ingrediente in una ricetta in unità intere o frazioni. A causa del mio meccanismo di completamento automatico, solo un numero è valido (dato che verrà visualizzato un menu a discesa). Queste linee sono valide:Qualche modo per migliorare questa espressione regolare?

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

la parte numerica della linea dovrebbe essere il suo gruppo in modo da poter analizzare che con il mio frazione parser. Tutto dopo la parte numerica dovrebbe essere un secondo gruppo. In un primo momento, ho provato questo:

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

Questo quasi funziona, ma "1 1/2 tazze" andranno analizzato come (1) (1/2 tazze) invece di (1 1/2) e (coppe). Dopo avermi grattato un po 'la testa, ho capito che questo era dovuto all'ordinamento della mia clausola "OR". (1) soddisfa \ d + e (. *) Soddisfa il resto. Così ho cambiato questo:

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

Questo funziona quasi, ma permette di stranezze, come "1 1/2/4 tazze" o "1/2 3 tazze". Così ho deciso di far rispettare una lettera come primo carattere dopo un'espressione numerica valida:

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

Nota Io corro questo in modalità case-insensitive. Ecco le mie domande:

  1. È possibile migliorare l'espressione? Non mi piace la lista "OR" per numero, frazione, frazione composta ma non riesco a pensare a un modo per consentire numeri interi, frazioni o frazioni composte.

  2. Sarebbe molto più bello se potessi restituire un gruppo per ogni parola dopo il componente numerico. Come un gruppo per (10 3/4), un gruppo per (tazze) e un gruppo per (a fette). Ci può essere un numero qualsiasi di parole dopo. È possibile?

Grazie!

+0

Oh oops, manca un altro caso .. L'importo può essere espresso in decimale. Quindi ho aggiunto un'altra clausola OR: ^ \ s * (\ d + \/\ d + | \ d + \ s * \ d + \/\ d + | \ d + | \ d * \. \ D) \ s * ($ | [az]. *) $ –

risposta

3

Bene, a me sembra che non siano necessarie condizioni OR (vedere sotto).

Per il bit numerica, si potrebbe ottenere via con:

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

che gestire tutti quei valori frazionari.

Continuerò a mantenere il decimale separato con una clausola OR poiché è probabile che complichi le cose. Quindi penso che probabilmente si potrebbe ottenere via con qualcosa come:

^\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. 

anche se che consente per un importo frazionario vuoto così si può essere meglio con quello che hai (intero, frazionata e decimali in separato clausole OR) .

preferisco il ([a-z].*)?$ costrutto per ($|[a-z].*)$ me stesso, ma che potrebbe essere solo un'avversione sul mio passato di avere più marcatori di fine linea nella mia RE :-)


Ma, in tutta onestà, io ti penso potrebbe cercare di schiacciare una mosca con una testata termonucleare qui.

Sei davvero necessario limitare ciò che viene inserito. Ho visto ricette che richiedono a pinch of salt e a handful of sultanas. Personalmente penso che potresti essere restrittivo in ciò che permetterò. Avrei un campo in forma libera per la quantità e un menu a discesa per il tipo di cibo (in realtà probabilmente avrei solo permesso la forma libera per il lotto a meno che non stavo offrendo la possibilità di cercare le ricette in base a ciò che è nel frigo).

+0

Forse stiamo usando parser diversi, ma questo non corrisponde a nessuno dei miei esempi sopra .. Ma penso di vedere cosa stai cercando di fare con il punto interrogativo .. –

+0

@Mike, non sono al corrente del motore Javascript RE come vorrei ma speravo che i bit descrittivi avessero superato l'idea. – paxdiablo

+0

Sì, guardando la tua espressione penso che dovrebbe funzionare anche, ma per qualche ragione non lo fa :) Sto usando RegExTester.com per testare le cose. –

1

Credo che questa regex dovrebbe fare ciò che si vuole:

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

Per corrispondere le parole specifiche si dovrebbe solo fare una spaccatura sul spazi dopo il parsing. Ci sono alcune cose che non vuoi fare con le regex;)

+0

Sì, funziona, solo nessun supporto decimale .. e ho cambiato (. *) In ([az]. *) Per eliminare cose come 1/2 bicchieri/tazze .. –

+0

In realtà probabilmente ($ | [az]. *) è ancora meglio, dal momento che non voglio richiedere nulla dopo la parte numerica. –

+0

Ah si. Se si desidera il supporto decimale di invece dovrebbe essere usato [\ d.] + '. È difficile mantenerlo completamente contenuto in una regex se si desidera aggiungere regole complesse. – Wolph

Problemi correlati