209 votes

Pourquoi les expressions régulières sont-elles si controversées ?

Lorsqu'il s'agit d'explorer les expressions régulières (également connues sous le nom de RegEx-es), de nombreuses personnes semblent considérer les expressions régulières comme le Saint Graal. Quelque chose qui a l'air si compliqué doit être la réponse à n'importe quelle question. Ils ont tendance à penser que tous les problèmes peuvent être résolus à l'aide des expressions régulières.

D'un autre côté, de nombreuses personnes essaient d'éviter à tout prix les expressions régulières. Ils essaient de trouver un moyen de contourner les expressions régulières et acceptent un codage supplémentaire juste pour le plaisir, même si une expression régulière serait une solution plus compacte.

Pourquoi les expressions régulières sont-elles si controversées ? Y a-t-il des malentendus généralisés sur leur fonctionnement ? Ou s'agit-il d'une croyance répandue selon laquelle les expressions régulières sont généralement lentes ?

133voto

Kyle Cronin Points 35834

Je ne pense pas que les gens s'opposent aux expressions régulières parce qu'elles sont lentes, mais plutôt parce qu'elles sont difficiles à lire et à écrire, et qu'il est délicat de les utiliser correctement. Bien qu'il existe des situations où les expressions régulières fournissent une solution efficace et compacte au problème, elles sont parfois utilisées dans des situations où il est préférable d'utiliser une section de code facile à lire et à maintenir.

121voto

Joel Berger Points 14203

Faire en sorte que les expressions rationnelles puissent être maintenues

Une avancée majeure vers la démystification des motifs précédemment appelés "expressions régulières" est l'outil Perl /x drapeau regex - parfois écrit (?x) lorsqu'il est intégré - qui autorise les espaces blancs (saut de ligne, indentation) et les commentaires. Cela améliore considérablement la lisibilité et donc la maintenabilité. Les espaces blancs permettent un découpage cognitif, de sorte que vous pouvez voir ce qui est regroupé avec ce qui est regroupé.

Les modèles modernes prennent également en charge les références secondaires relativement numérotées et nommées. Cela signifie que vous n'avez plus besoin de compter les groupes de capture pour savoir que vous avez besoin de $4 o \7 . Cela permet de créer des modèles qui peuvent être inclus dans d'autres modèles.

Voici un exemple de groupe de capture relativement numéroté :

$dupword = qr{ \\b (?: ( \\w+ ) (?: \\s+ \\g{-1} )+ ) \\b }xi;
$quoted  = qr{ ( \["'\] ) $dupword  \\1 }x;

Voici un exemple de l'approche supérieure des captures nominatives :

$dupword = qr{ \b (?: (?<word> \w+ ) (?: \s+ \k<word> )+ ) \b }xi;
$quoted  = qr{ (?<quote> ["'] ) $dupword  \g{quote} }x;

Les expressions rationnelles grammaticales

Le meilleur de tous Ces captures nommées peuvent être placées à l'intérieur d'un (?(DEFINE)...) afin que vous puissiez séparer la déclaration de l'exécution des éléments individuels nommés de vos motifs. Ils se comportent ainsi comme des sous-programmes à l'intérieur du motif.
Un bon exemple de ce type de "regex grammaticale" se trouve dans le document suivant cette réponse y celui-ci . Elles ressemblent davantage à une déclaration grammaticale.

Comme le rappelle ce dernier :

veillez à ne jamais écrire de motifs de bruit de ligne. Vous n'êtes pas obligé de le faire, et vous ne devriez pas le faire. Aucun langage de programmation ne peut être maintenable s'il interdit les espaces blancs, les commentaires, les sous-programmes ou les identificateurs alphanumériques. Utilisez donc tous ces éléments dans vos modèles.

On ne saurait trop insister sur ce point. Bien entendu, si vous n'utilisez pas ces éléments dans vos modèles, vous créerez souvent un cauchemar. Mais si vous faire Mais il n'est pas nécessaire de les utiliser.

Voici un autre exemple de modèle grammatical moderne, qui permet d'analyser la RFC 5322 : utiliser 5.10.0 ;

$rfc5322 = qr{

   (?(DEFINE)

     (?<address>         (?&mailbox) | (?&group))
     (?<mailbox>         (?&name_addr) | (?&addr_spec))
     (?<name_addr>       (?&display_name)? (?&angle_addr))
     (?<angle_addr>      (?&CFWS)? < (?&addr_spec) > (?&CFWS)?)
     (?<group>           (?&display_name) : (?:(?&mailbox_list) | (?&CFWS))? ; (?&CFWS)?)
     (?<display_name>    (?&phrase))
     (?<mailbox_list>    (?&mailbox) (?: , (?&mailbox))*)

     (?<addr_spec>       (?&local_part) \@ (?&domain))
     (?<local_part>      (?&dot_atom) | (?&quoted_string))
     (?<domain>          (?&dot_atom) | (?&domain_literal))
     (?<domain_literal>  (?&CFWS)? \[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?
                                   \] (?&CFWS)?)
     (?<dcontent>        (?&dtext) | (?&quoted_pair))
     (?<dtext>           (?&NO_WS_CTL) | [\x21-\x5a\x5e-\x7e])

     (?<atext>           (?&ALPHA) | (?&DIGIT) | [!#\$%&'*+-/=?^_`{|}~])
     (?<atom>            (?&CFWS)? (?&atext)+ (?&CFWS)?)
     (?<dot_atom>        (?&CFWS)? (?&dot_atom_text) (?&CFWS)?)
     (?<dot_atom_text>   (?&atext)+ (?: \. (?&atext)+)*)

     (?<text>            [\x01-\x09\x0b\x0c\x0e-\x7f])
     (?<quoted_pair>     \\ (?&text))

     (?<qtext>           (?&NO_WS_CTL) | [\x21\x23-\x5b\x5d-\x7e])
     (?<qcontent>        (?&qtext) | (?&quoted_pair))
     (?<quoted_string>   (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*
                          (?&FWS)? (?&DQUOTE) (?&CFWS)?)

     (?<word>            (?&atom) | (?&quoted_string))
     (?<phrase>          (?&word)+)

     # Folding white space
     (?<FWS>             (?: (?&WSP)* (?&CRLF))? (?&WSP)+)
     (?<ctext>           (?&NO_WS_CTL) | [\x21-\x27\x2a-\x5b\x5d-\x7e])
     (?<ccontent>        (?&ctext) | (?&quoted_pair) | (?&comment))
     (?<comment>         \( (?: (?&FWS)? (?&ccontent))* (?&FWS)? \) )
     (?<CFWS>            (?: (?&FWS)? (?&comment))*
                         (?: (?:(?&FWS)? (?&comment)) | (?&FWS)))

     # No whitespace control
     (?<NO_WS_CTL>       [\x01-\x08\x0b\x0c\x0e-\x1f\x7f])

     (?<ALPHA>           [A-Za-z])
     (?<DIGIT>           [0-9])
     (?<CRLF>            \x0d \x0a)
     (?<DQUOTE>          ")
     (?<WSP>             [\x20\x09])
   )

   (?&address)

}x;

N'est-ce pas remarquable - et splendide ? Vous pouvez prendre une grammaire de style BNF et la traduire directement en code sans perdre sa structure fondamentale !

Si les modèles grammaticaux modernes encore ne vous suffisent pas, alors La brillante de Damian Conway Regexp::Grammars module offre une syntaxe encore plus propre, ainsi qu'un débogage supérieur. Voici le même code pour l'analyse de la RFC 5322, refondu en un motif de ce module :

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;
use Data::Dumper "Dumper";

my $rfc5322 = do {
    use Regexp::Grammars;    # ...the magic is lexically scoped
    qr{

    # Keep the big stick handy, just in case...
    # <debug:on>

    # Match this...
    <address>

    # As defined by these...
    <token: address>         <mailbox> | <group>
    <token: mailbox>         <name_addr> | <addr_spec>
    <token: name_addr>       <display_name>? <angle_addr>
    <token: angle_addr>      <CFWS>? \< <addr_spec> \> <CFWS>?
    <token: group>           <display_name> : (?:<mailbox_list> | <CFWS>)? ; <CFWS>?
    <token: display_name>    <phrase>
    <token: mailbox_list>    <[mailbox]> ** (,)

    <token: addr_spec>       <local_part> \@ <domain>
    <token: local_part>      <dot_atom> | <quoted_string>
    <token: domain>          <dot_atom> | <domain_literal>
    <token: domain_literal>  <CFWS>? \[ (?: <FWS>? <[dcontent]>)* <FWS>?

    <token: dcontent>        <dtext> | <quoted_pair>
    <token: dtext>           <.NO_WS_CTL> | [\x21-\x5a\x5e-\x7e]

    <token: atext>           <.ALPHA> | <.DIGIT> | [!#\$%&'*+-/=?^_`{|}~]
    <token: atom>            <.CFWS>? <.atext>+ <.CFWS>?
    <token: dot_atom>        <.CFWS>? <.dot_atom_text> <.CFWS>?
    <token: dot_atom>        <.CFWS>? <.dot_atom_text> <.CFWS>?
    <token: dot_atom_text>   <.atext>+ (?: \. <.atext>+)*

    <token: text>            [\x01-\x09\x0b\x0c\x0e-\x7f]
    <token: quoted_pair>     \\ <.text>

    <token: qtext>           <.NO_WS_CTL> | [\x21\x23-\x5b\x5d-\x7e]
    <token: qcontent>        <.qtext> | <.quoted_pair>
    <token: quoted_string>   <.CFWS>? <.DQUOTE> (?:<.FWS>? <.qcontent>)*
                             <.FWS>? <.DQUOTE> <.CFWS>?

    <token: word>            <.atom> | <.quoted_string>
    <token: phrase>          <.word>+

    # Folding white space
    <token: FWS>             (?: <.WSP>* <.CRLF>)? <.WSP>+
    <token: ctext>           <.NO_WS_CTL> | [\x21-\x27\x2a-\x5b\x5d-\x7e]
    <token: ccontent>        <.ctext> | <.quoted_pair> | <.comment>
    <token: comment>         \( (?: <.FWS>? <.ccontent>)* <.FWS>? \)
    <token: CFWS>            (?: <.FWS>? <.comment>)*
                             (?: (?:<.FWS>? <.comment>) | <.FWS>)

    # No whitespace control
    <token: NO_WS_CTL>       [\x01-\x08\x0b\x0c\x0e-\x1f\x7f]

    <token: ALPHA>           [A-Za-z]
    <token: DIGIT>           [0-9]
    <token: CRLF>            \x0d \x0a
    <token: DQUOTE>          "
    <token: WSP>             [\x20\x09]

    }x;

};

while (my $input = <>) {
    if ($input =~ $rfc5322) {
        say Dumper \%/;       # ...the parse tree of any successful match
                              # appears in this punctuation variable
    }
}

Il y a beaucoup de bonnes choses dans les perlre page de manuel mais ces améliorations spectaculaires des caractéristiques fondamentales de conception des expressions rationnelles ne sont en aucun cas limitées au seul langage Perl. En effet, les les pcrepattern page de manuel est peut-être plus facile à lire et couvre le même territoire.

Les modèles modernes n'ont pratiquement rien à voir avec les choses primitives que l'on vous a enseignées dans votre cours sur les automates finis.

68voto

Chas. Owens Points 40887

Les regex sont un outil formidable, mais les gens pensent "Hé, quel outil formidable, je vais l'utiliser pour faire X !" où X est quelque chose pour lequel un autre outil est meilleur (généralement un analyseur syntaxique). C'est le problème classique de l'utilisation d'un marteau là où l'on a besoin d'un tournevis.

53voto

Barry Brown Points 9774

Presque toutes les personnes que je connais et qui utilisent régulièrement des expressions régulières (jeu de mots) viennent d'un environnement Unix où elles utilisent des outils qui traitent les expressions régulières comme des constructions de programmation de première classe, tels que grep, sed, awk et Perl. Étant donné que l'utilisation d'une expression régulière n'entraîne pratiquement aucune surcharge syntaxique, leur productivité augmente considérablement lorsqu'ils le font.

En revanche, les programmeurs qui utilisent des langages dans lesquels les expressions régulières constituent une bibliothèque externe ont tendance à ne pas tenir compte de ce que les expressions régulières peuvent apporter. Le "coût du temps" du programmeur est si élevé que soit a) les ER n'ont jamais fait partie de leur formation, soit b) ils ne "pensent" pas en termes d'ER et préfèrent se rabattre sur des modèles plus familiers.

44voto

Bill Karwin Points 204877

Les expressions régulières vous permettent d'écrire une machine à états finis (FSM) personnalisée de manière compacte, pour traiter une chaîne d'entrée. Il y a au moins deux raisons pour lesquelles l'utilisation des expressions régulières est difficile :

  • Le développement de logiciels à l'ancienne implique beaucoup de planification, de modèles sur papier et de réflexion approfondie. Les expressions régulières s'intègrent très bien dans ce modèle, car pour écrire correctement une expression efficace, il faut beaucoup la regarder, visualiser les chemins du FSM.

    Les développeurs de logiciels modernes préfèrent de loin marteler le code et utiliser un débogueur pour en suivre l'exécution, afin de vérifier si le code est correct. Les expressions régulières ne s'adaptent pas très bien à ce style de travail. Une "exécution" d'une expression régulière est en fait une opération atomique. Il est difficile d'observer l'exécution par étapes dans un débogueur.

  • Il est trop facile d'écrire une expression régulière qui accepte accidentellement plus d'entrées que prévu. La valeur d'une expression régulière n'est pas vraiment de correspondre à une entrée valide, mais de ne correspond pas à une entrée non valide . Les techniques permettant de réaliser des "tests négatifs" pour les expressions régulières ne sont pas très avancées, ou du moins pas très répandues.

    Cela revient à dire que les expressions régulières sont difficiles à lire. Rien qu'en regardant une expression régulière, il faut beaucoup de concentration pour visualiser toutes les entrées possibles qui devraient être rejetées, mais qui sont acceptées par erreur. Avez-vous déjà essayé de déboguer quelqu'un d'autrui code d'expression régulière ?

S'il existe aujourd'hui une résistance à l'utilisation des expressions régulières parmi les développeurs de logiciels, je pense que c'est principalement dû à ces deux facteurs.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X