2009-08-27 4 views
0

La langue est Ruby, voici ma session irbPourquoi la dernière expression de mon expression régulière concatène-t-elle avec la première?

expr = /\Aselect from (\D+)(?: (?:where|&&) (\D+) (\S+) (\S+))*(?: order by (\D+) (asc|desc))?\Z/ 
=> /\Aselect from (\D+)(?: (?:where|&&) (\D+) (\S+) (\S+))*(?: order by (\D+) (asc|desc))?\Z/ 

/> str = "select from Entity order by value desc" 
=> "select from Entity order by value desc" 

/> expr =~ str 
=> 0 

/> $1 
=> "Entity order by value desc" 

/> $2 
=> nil 

Je ne comprends pas pourquoi je reçois « pour l'entité en valeur desc » $ 1. Le comportement souhaité ici serait d'obtenir $ 1 => "Entity", $ 2 => "value", $ 3 => "desc". Qu'est-ce que je fais mal? Comment puis-je modifier cette expression régulière pour obtenir ces résultats?

Merci

Répondre

4

\ D est « non chiffres », qui couvre les espaces entre les mots, ainsi que les mots suivants. Essayez (\ S +) à la place. [Modifier] Désolé, j'ai raté la question à la fin. Ce qui précède répond à la question "pourquoi cela arrive-t-il?", Mais pas "comment puis-je réaliser ce que je voulais?". Voici une façon, sans passer par toutes les autres clauses avec. *

/\Aselect from (\S+).*(?:order by (\S+) (asc|desc)?)?\Z/ 

Depuis SQL est assez libre avec espacement et comme entre les mots clés, vous voudrez peut-être le rendre plus illisible et utiliser \ s + au lieu des espaces littérales. Autrement dit, l'expression est-ne correspondraient pas:

"select from  Fred" 

mais il si vous avez/\ ASÉLECTIONNER \ s + \ s + ....

1

Le (\D+) est avide et a mangé le reste de la chaîne. Puisque tout le reste de votre expression est facultatif (* ou?), Il n'est pas nécessaire de faire correspondre celle-ci pour que l'expression réussisse.

Ma suggestion est de rendre vos matchs moins gourmands. Par exemple (\D+?) correspondra et capturera toutes les non-chiffres une ou plusieurs fois, mais aussi peu de fois que nécessaire pour faire une correspondance réussie.