2010-08-09 1 views
13

J'essaye de créer une fonction de Python qui peut prendre une description anglaise simple d'une expression régulière et renvoyer l'expression régulière à l'appelant. Actuellement, je pense à la description au format YAML. Donc, nous pouvons stocker la description comme une variable de chaîne brute, qui est transmise à cette autre fonction et la sortie de cette fonction est ensuite passée au module 're'. Voici un exemple assez simpliste:est-il besoin d'une manière plus déclarative d'exprimer des expressions régulières? :)

# a(b|c)d+e* 
re1 = """ 
- literal: 'a' 
- one_of: 'b,c' 
- one_or_more_of: 'd' 
- zero_or_more_of: 'e' 
""" 
myre = re.compile(getRegex(re1)) 
myre.search(...) 

etc.

Quelqu'un pense que quelque chose de ce genre serait d'une utilisation plus large? Connaissez-vous des paquets déjà existants qui peuvent le faire? Quelles sont les limites que vous voyez à cette approche? Quelqu'un pense-t-il, ayant la chaîne déclarative dans le code, le rendrait plus maintenable?

+0

JSON ou XML peut-être? DTD ou XSD peut également décrire une structure de données bien. – codymanix

+7

Donc, au lieu d'une expression rationnelle complexe prenant une ligne entière, il faudra une page entière :) –

+4

Les gens qui connaissent des expressions régulières sont à l'aise avec elle, mais pour tout le monde, il semble que l'alphabet a vomi. Cela pourrait être un problème, mais je ne suis pas sûr. Après tout, vous pouvez dire la même chose des langages de programmation pour les personnes qui programment vs perople qui ne le font pas. Il pourrait être agréable de le faire avec des objets et des fonctions de chaînes de caractères, mais je ne suis pas sûr de ce que la meilleure façon de mettre en œuvre ce serait. +1 pour l'innovation tout de même. – psicopoo

Répondre

2

Pour les développeurs essayant d'écrire des expressions régulières qui sont faciles pour grok et maintenir, je me demande si ce genre d'approche offrirait tout ce que re.VERBOSE ne fournit pas déjà.

Pour les débutants, votre idée pourrait avoir un certain attrait. Cependant, avant de suivre ce chemin, vous pouvez essayer de simuler la syntaxe déclarative pour des expressions régulières plus compliquées en utilisant des groupes de capture, des ancres, des assertions anticipées, etc. Un défi est que vous pourriez vous retrouver avec une syntaxe déclarative qui est tout aussi difficile à retenir que le langage regex lui-même.

Vous pourriez également penser à d'autres façons d'exprimer des choses. Par exemple, la première idée qui m'est venue à l'esprit était d'exprimer une regex en utilisant des fonctions avec des noms courts et faciles à mémoriser. Par exemple:

from refunc import * 

pattern = Compile(
    'a', 
    Capture(
     Choices('b', 'c'), 
     N_of('d', 1, Infin()), 
     N_of('e', 0, Infin()), 
    ), 
    Look_ahead('foo'), 
) 

Mais quand je vois cela en action, cela me semble être une douleur. De nombreux aspects de regex sont assez intuitifs - par exemple, + pour signifier «un ou plusieurs». Une option serait une approche hybride, permettant à votre utilisateur de mélanger les parties de regex qui sont déjà simples avec des fonctions pour les bits les plus ésotériques. Je voudrais ajouter que dans mon expérience, les expressions régulières sont sur l'apprentissage d'un processus de pensée. Se familiariser avec la syntaxe est la partie facile.

6

C'est en fait assez similaire (identique?) À la façon dont un lexer/parser fonctionne. Si vous aviez une grammaire définie, vous pourriez probablement écrire un analyseur sans trop de problèmes. Par exemple, vous pouvez écrire quelque chose comme ceci:

<expression> :: == <rule> | <rule> <expression> | <rule> " followed by " <expression> 
<rule>  :: == <val> | <qty> <val> 
<qty>  :: == "literal" | "one" | "one of" | "one or more of" | "zero or more of" 
<val>  :: == "a" | "b" | "c" | "d" | ... | "Z" | 

Cette description est loin d'être parfaite. Pour plus d'informations, jetez un oeil à this BNF of the regex language. Vous pouvez alors regarder lexing et parsing l'expression.

Si vous l'avez fait de cette façon, vous pourriez probablement vous rapprocher un peu plus de Natural Language/versions anglaises de regex. Je peux voir un outil comme celui-ci utile, mais comme il a été dit précédemment, principalement pour les débutants. La principale limite à cette approche serait la quantité de code que vous devez écrire pour traduire la langue en regex (et/ou vice versa). D'un autre côté, je pense qu'un outil de traduction bidirectionnelle serait en fait plus idéal et plus utile. Être capable de prendre une regex et de le traduire en anglais pourrait être beaucoup plus utile pour détecter les erreurs.

Bien sûr, il ne faut pas trop de temps pour ramasser regex car la syntaxe est généralement laconique et la plupart des significations sont assez explicites, du moins si vous utilisez | ou || comme OR dans votre langue, et vous pensez * multiplier par 0-N, + en ajoutant 0-N.

Bien que je ne me dérangerait pas parfois taper « trouver un ou plusieurs « a » suivi de trois chiffres ou « b » puis « c » »

+0

En réponse à votre 'Être capable de prendre une regex et le tourner en anglais pourrait être beaucoup plus utile pour détecter les erreurs. Paramètre 're.DEBUG' avec python en mode repl. – Daenyth

+0

@Daenyth - Je suis conscient de ce mode, bien que je n'ai pas eu de raison de l'utiliser, et je ne peux pas dire que c'est beaucoup mieux que l'expression rationnelle originale, à moins que ce soit une regex extrêmement compliquée. –

6

S'il vous plaît jeter un oeil à pyparsing. La plupart des problèmes que vous décrivez avec les ER sont les mêmes que ceux qui m'ont inspiré pour écrire ce paquet.

Voici quelques caractéristiques spécifiques de pyparsing du chapitre "What's so special about pyparsing?" du livre électronique O'Reilly.

+1

Vous me battez en une seconde! BTW, merci d'avoir écrit pyparsing :) –

2

peut-être pas exactement ce que vous demandez, mais il y a une façon comment écrire regexes manière plus lisible (VERBOSE, peu X drapeau):

rex_name = re.compile(""" 
    [A-Za-z] # first letter 
    [a-z]+  # the rest 
""", re.X) 

rex_name.match('Joe')