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) | (?"ed_string))
(?<domain> (?&dot_atom) | (?&domain_literal))
(?<domain_literal> (?&CFWS)? \[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?
\] (?&CFWS)?)
(?<dcontent> (?&dtext) | (?"ed_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) | (?"ed_pair))
(?<quoted_string> (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*
(?&FWS)? (?&DQUOTE) (?&CFWS)?)
(?<word> (?&atom) | (?"ed_string))
(?<phrase> (?&word)+)
# Folding white space
(?<FWS> (?: (?&WSP)* (?&CRLF))? (?&WSP)+)
(?<ctext> (?&NO_WS_CTL) | [\x21-\x27\x2a-\x5b\x5d-\x7e])
(?<ccontent> (?&ctext) | (?"ed_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.