2010-08-31 8 views
4

Compte tenu des expressions régulières suivantes:Déterminer la spécificité de l'expression régulière

- [email protected][a-z]+\.[a-z]+ 
- [a-z][email protected][a-z]+\.[a-z]+ 
- .* 

La chaîne [email protected] correspondra évidemment les trois expressions régulières. Dans l'application que je développe, nous ne nous intéressons qu'au match le plus spécifique. Dans ce cas, c'est évidemment le premier.
Malheureusement, il semble y avoir aucun moyen de le faire. Nous utilisons PCRE et je n'ai pas trouvé un moyen de le faire et une recherche sur Internet n'a pas été fructueuse.
Une façon possible serait de garder les expressions régulières triées selon la spécificité décroissante, puis de simplement prendre la première correspondance. Bien sûr, la prochaine question serait de savoir comment trier le tableau des expressions régulières. Ce n'est pas une option de donner la responsabilité à l'utilisateur final pour s'assurer que le tableau est trié. Donc j'espère que vous pourriez m'aider ici ...

Merci!

Paul

+1

Ce n'est pas évident pour moi que le premier est «le plus spécifique». Quelle est votre définition de «plus spécifique» définir un algorithme pour cela et vous serez à mi-chemin là. Mais il me semble que la façon simple de le faire (comme Flex) est que vous avez plusieurs expressions qui correspondent exactement puis choisissez le premier défini dans vos données. –

Répondre

4

Mon instinct dit que non seulement ce problème difficile, tant en termes de coût de calcul et de la difficulté de mise en œuvre, mais il peut être impossible à résoudre de toute façon réaliste. Considérons les deux expressions régulières suivantes pour accepter la chaîne [email protected]

 
    [email protected][a-z]+\.[a-z]+ 
    [a-z][email protected]

Lequel d'entre eux est plus précis?

+0

Celui avec plus de constantes de caractères? Ou peut-être que vous pourriez construire automatiquement une expression régulière qui était l'intersection de tous les deux. Autrement dit, si RE (a) définit le langage L1 et RE (b) définit le langage L2, construisons une expression régulière RE (a, b) qui définit une langue INTERSECTION (L1, L2). – Avi

5

Je travaille sur une réponse au même problème, ce que j'ai trouvé jusqu'à présent est ici: http://maple.cs.umbc.edu/~don/projects/ugrad-ht/dminer-ugradthesis.pdf

Il est un document de recherche de deuxième cycle en Perl regex, il a une définition pratique pour « plus spécifique regex 'et déclenche un avertissement s'il y a deux expressions regex de spécificité égale. Il est basé en partie sur le setfile de SELinux, mais vise à être plus rapide et plus précis. Setfile laisse le soin à l'utilisateur de faire en sorte que les correspondances vont du plus spécifique au moins spécifique, et prend la première correspondance. Cela peut causer certains problèmes que le document de recherche vise à résoudre.

Fondamentalement, la correspondance la plus spécifique est celle qui n'est pas un sur-ensemble d'une autre correspondance. La difficulté dans la solution est de déterminer quels ensembles sont des sur-ensembles d'autres ensembles; bien sûr, la réponse à cela dépend des circonstances pour lesquelles l'expression rationnelle est nécessaire. Une fois que vous avez la liste des super-ensembles, il devient alors inutile d'éliminer les correspondances. Donc, avec les expressions regex '^ /. *', '^/Usr /.*' et '^/home /.*', '^ /. *' Est un sur-ensemble des deux autres, tandis que les deux autres sont mutuellement exclusif. Dans une implémentation correcte, si les deux autres n'étaient pas mutuellement exclusifs (manquant le '^'), et aucun n'est un sur-ensemble de l'autre, un avertissement ou une erreur doit être émis à l'utilisateur. Pour une chaîne donnée, pour tester une correspondance, elle doit d'abord être vérifiée par rapport aux surensembles (dans ce cas '^ /. *'), Si elle ne correspond pas au surensemble, elle ne peut correspondre à aucun modèle spécifique. Si cela correspond, alors un test contre chacun des enfants du surensemble devrait être exécuté (ces ensembles peuvent aussi être des surensembles d'ensembles supplémentaires). Si elle ne correspond à aucun des enfants, alors l'expression rationnelle la plus spécifique est le surensemble ('^ /. *'). Si elle correspond à l'un des enfants, le processus doit se répéter avec les petits-enfants associés, jusqu'à ce qu'il n'y ait plus d'ensembles spécifiques ou qu'aucun ensemble spécifique ne corresponde.

Il peut être suffisant de ne pas émettre d'avertissement sur les non-super-ensembles non mutuellement exclusifs, à moins qu'une tentative de concordance de chaîne ne puisse être résolue. Considérons l'ensemble des expressions regex: '^ /. *', '/usr.*' et '/home.*'. La chaîne '/ home/usr' correspondrait aux trois, et une tentative de correspondance de celle-ci devrait générer une erreur, car il n'est pas clair si '/usr.*' ou '/home.*' est le plus régulier expression.En fonction des raisons pour lesquelles vous avez besoin de la solution, renvoyer une liste d'expressions régulières qui ne sont pas des sur-ensembles de toute autre regex correspondante peut être la solution idéale. Dans ce cas, '/ home/usr' devrait retourner '/home.*' et '/usr.*', mais pas '^ /. *'.

Le document ne contient aucun exemple de code, mais décrit uniquement la solution en termes abstraits. Je vais essayer d'écrire du code pour l'implémenter, ou peut-être envoyer un e-mail à l'auteur pour voir si je peux obtenir le code, si je reçois quelque chose qui fonctionne, je le posterai ici.

+0

Fouillant sur le site de l'auteur, j'ai trouvé ceci: Ce n'est pas GPL, alors ne l'utilisez pas sans le contacter d'abord. http://maple.cs.umbc.edu/~don/projects/ugrad-ht/regexfind.py – Perkins

+0

Les URL spécifiées ne sont pas valides –

0

Je pense à un problème similaire pour un analyseur de route de projets PHP. Après avoir lu les autres réponses et commentaires ici, et en pensant aussi au coût impliqué je pourrais aller dans une autre direction tout à fait.

Une solution cependant, serait de simplement trier la liste d'expressions régulières dans l'ordre de sa longueur de chaîne.

Ce n'est pas parfait, mais simplement en supprimant les [] -groupes ce serait beaucoup plus proche. Sur le premier exemple dans la question, il serait cette liste:

- [email protected][a-z]+\.[a-z]+ 
- [a-z][email protected][a-z]+\.[a-z]+ 
- .* 

Pour cela, après avoir retiré le contenu de tout [] -Groupe:

- [email protected]+\.+ 
- [email protected]+\.+ 
- .* 

Même chose pour le second exemple dans une autre réponse, avec les [] -groupes complètement enlevés et triées par longueur, ceci:

[email protected][a-z]+\.[a-z]+ 
[a-z][email protected] 

deviendrais triés comme:

[email protected] 
[email protected]+\.+ 

C'est une assez bonne solution au moins pour moi, si je choisis de l'utiliser. L'inconvénient serait la surcharge de supprimer tous les groupes de [] avant de trier et d'appliquer le tri sur la liste non modifiée des expressions rationnelles, mais bon - vous ne pouvez pas tout obtenir.