.\" Automatically generated by Pod::Man 2.09 (Pod::Simple 3.04) .\" .\" Standard preamble: .\" ======================================================================== .de Sh \" Subsection heading .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. | will give a .\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to .\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' .\" expand to `' in nroff, nothing in troff, for use with C<>. .tr \(*W-|\(bv\*(Tr .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .\" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .hy 0 .if n .na .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "PERLRETUT 1" .TH PERLRETUT 1 "2006-04-24" "DocFr" "User Contributed Perl Documentation" .SH "NAME/NOM" .IX Header "NAME/NOM" perlretut \- Tutoriel des expressions rationnelles en Perl .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fBRemarque sur la traduction\fR\ : on emploie couramment le terme \&\*(L"expression re\*'gulie\*`re\*(R" car le terme anglais est \*(L"regular expression\*(R" qui s'abre\*`ge en \*(L"regexp\*(R". Mais ne nous y trompons pas, en franc\*,ais, ce sont bien des \*(L"expressions rationnelles\*(R". .PP Ce document propose un tutoriel dans le but de comprendre, cre\*'er et utiliser des expressions rationnelles en Perl. Il sert de comple\*'ment a\*` la documentation de re\*'fe\*'rence sur les expressions rationnelles, perlre. Les expressions rationnelles font partie inte\*'grante des ope\*'rateurs \f(CW\*(C`m//\*(C'\fR, \f(CW\*(C`s///\*(C'\fR, \f(CW\*(C`qr//\*(C'\fR et \f(CW\*(C`split\*(C'\fR, donc ce tutoriel a aussi des recoupements avec \*(L"Ope\*'rateurs d'expression rationnelle\*(R" in perlop et \*(L"split\*(R" in perlfunc. .PP Perl est largement reconnu pour ses capacite\*'s de manipulation de textes et les expressions rationnelles y sont pour beaucoup. Les expressions rationnelles en Perl permettent une flexibilite\*' et une efficience inconnues dans la plupart des autres langages. La mai\*^trise des expressions rationnelles me\*^me les plus simples vous permettra de manipuler du texte avec une surprenante facilite\*'. .PP Qu'est\-ce qu'une expression rationnelle ? Une expression rationnelle est tout simplement une chai\*^ne de caracte\*`res qui de\*'crit un motif. La notion de motif est couramment utilise\*'e de nos jours. Par exemple, les motifs utilise\*'s par un moteur de recherche pour trouver des pages web ou les motifs utilise\*'s pour lister les fichiers dans un re\*'pertoire, e.g. \f(CW\*(C`ls *.txt\*(C'\fR ou \f(CW\*(C`dir *.*\*(C'\fR. En Perl, les motifs d'expressions rationnelles sont utilise\*'s pour chercher dans des chai\*^nes de caracte\*`res, pour extraire certaines parties d'une chai\*^ne et pour re\*'aliser des ope\*'rations de recherche et de remplacement. .PP Les expressions rationnelles ont la re\*'putation d'e\*^tre abstraite et difficile a\*` comprendre. Les expressions rationnelles sont construites par assemblage de concepts simples tels que des conditions et des boucles qui ne sont pas plus complique\*'s a\*` comprendre que les conditions \f(CW\*(C`if\*(C'\fR et les boucles \f(CW\*(C`while\*(C'\fR du langage Perl lui\-me\*^me. En fait, le ve\*'ritable enjeu dans l'apprentissage des expressions rationnelles re\*'side dans la compre\*'hension de la notation laconique utilise\*'e pour exprimer ces concepts. .PP Ce tutoriel aplanit la courbe d'apprentissage en pre\*'sentant les concepts des expressions rationnelles, ainsi que leur notation, un par un et accompagne\*'s d'exemples. La premie\*`re partie de ce tutoriel commence par la simple recherche de mots pour aboutir aux concepts de base des expressions rationnelles. Si vous mai\*^triser cette premie\*`re partie, vous aurez tous les outils ne\*'cessaires pour re\*'soudre 98% de vos besoins. La seconde partie de ce tutoriel est destine\*'e a\*` ceux qui sont de\*'ja\*` a\*` l'aise avec les bases et qui recherche des outils plus puissants. Elle explique les ope\*'rateurs les plus avance\*'s des expressions rationnelles ainsi que les dernie\*`res innovations de la version 5.6.0. .PP Remarque\ : pour gagner du temps, 'expression rationnelle' est parfois abre\*'ge\*'e par regexp ou regex. Regexp est plus naturel (pour un anglophone) que regex mais est aussi plus dur a\*` prononcer (toujours pour un anglophone). Dans la documentation Perl, on oscille entre regexp et regex ; en Perl, il y a toujours plusieurs fac\*,ons d'abre\*'ger. Dans ce tutoriel en franc\*,ais, nous n'utiliserons que rarement regexp (N.d.t: me\*^me si l'abre\*'viation franc\*,aise donne exprat !). .SH "Partie 1: les bases" .IX Header "Partie 1: les bases" .Sh "Reconnaissance d'un mot simple" .IX Subsection "Reconnaissance d'un mot simple" L'expression rationnelle la plus simple est un simple mot ou, plus ge\*'ne\*'ralement, une chai\*^ne de caracte\*`res. Une expression rationnelle constitue\*'e d'un mot reconnai\*^t toutes les chai\*^nes qui contiennent ce mot\ : .PP .Vb 1 \& "Hello World" =~ /World/; # est reconnu .Ve .PP Que signifie cette instruction perl ? \f(CW"Hello World"\fR est une simple chai\*^ne de caracte\*`res entre guillemets. \f(CW\*(C`World\*(C'\fR est l'expression rationnelle et les \f(CW\*(C`//\*(C'\fR qui l'entourent (\f(CW\*(C`/World/\*(C'\fR) demandent a\*` perl d'en chercher une correspondance dans une chai\*^ne. L'ope\*'rateur \f(CW\*(C`=~\*(C'\fR associe la chai\*^ne avec l'expression rationnelle de recherche de correspondance et produit une valeur vraie s'il y a correspondance ou faux sinon. Dans notre cas, \f(CW\*(C`World\*(C'\fR correspond au second mot dans \&\f(CW"Hello World"\fR et donc l'expression est vraie. De telles expressions sont pratique dans des conditions\ : .PP .Vb 6 \& if ("Hello World" =~ /World/) { \& print "Il y a correspondance\en"; \& } \& else { \& print "Il n'y a pas correspondance\en"; \& } .Ve .PP Il existe de nombreuses variations utiles sur ce the\*`me. Le sens de la correspondance peut\-e\*^tre inverse\*'e en utilisant l'ope\*'rateur \&\f(CW\*(C`!~\*(C'\fR\ : .PP .Vb 6 \& if ("Hello World" !~ /World/) { \& print "Il n'y a pas correspondance\en"; \& } \& else { \& print "Il y a correspondance\en"; \& } .Ve .PP La chai\*^ne litte\*'rale dans l'expression rationnelle peut e\*^tre remplace\*'e par une variable\ : .PP .Vb 7 \& $greeting = "World"; \& if ("Hello World" =~ /$greeting/) { \& print "Il y a correspondance\en"; \& } \& else { \& print "Il n'y a pas correspondance\en"; \& } .Ve .PP Si vous recherchez dans la variable spe\*'ciale par de\*'faut \f(CW$_\fR, la partie \f(CW\*(C`$_ =~\*(C'\fR peut e\*^tre omise\ : .PP .Vb 7 \& $_ = "Hello World"; \& if (/World/) { \& print "Il y a correspondance\en"; \& } \& else { \& print "Il n'y a pas correspondance\en"; \& } .Ve .PP Et finalement, les de\*'limiteurs par de\*'faut \f(CW\*(C`//\*(C'\fR pour une recherche de correspondance peuvent e\*^tre remplace\*'s par n'importe quels autres de\*'limiteurs en les pre\*'fixant par un \f(CW'm'\fR\ : .PP .Vb 4 \& "Hello World" =~ m!World!; # correspond, de\*'limiteur '!' \& "Hello World" =~ m{World}; # correspond, notez le couple '{}' \& "/usr/bin/perl" =~ m"/perl"; # correspond apre\*`s '/usr/bin' \& # '/' devient un caracte\*`re comme un autre .Ve .PP \&\f(CW\*(C`/World/\*(C'\fR, \f(CW\*(C`m!World!\*(C'\fR et \f(CW\*(C`m{World}\*(C'\fR repre\*'sentent tous la me\*^me chose. Lorsque, par exemple, \f(CW""\fR est utilise\*' comme de\*'limiteurs, la barre oblique \f(CW'/'\fR devient un caracte\*`re ordinaire et peut e\*^tre utilise\*' dans une expression rationnelle sans proble\*`me. .PP Regardons maintenant comment diffe\*'rentes expressions rationnelles peuvent ou non trouver une correspondance dans \f(CW"Hello World"\fR\ : .PP .Vb 4 \& "Hello World" =~ /world/; # ne correspond pas \& "Hello World" =~ /o W/; # correspond \& "Hello World" =~ /oW/; # ne correspond pas \& "Hello World" =~ /World /; # ne correspond pas .Ve .PP La premie\*`re expression rationnelle \f(CW\*(C`world\*(C'\fR ne correspond pas car les expressions rationnelles sont sensibles a\*` la casse. La deuxie\*`me expression rationnelle trouve une correspondance car la sous\-chai\*^ne \&\f(CW'o\ W'\fR apparai\*^t dans la chai\*^ne \f(CW"Hello\ World"\fR. Le caracte\*`re espace ' ' est traite\*' comme n'importe quel autre caracte\*`re dans une expression rationnelle et il est ne\*'cessaire ici pour trouver une correspondance. L'absence du caracte\*`re espace explique la non-reconnaissance de la troisie\*`me expression rationnelle. La quatrie\*`me expression rationnelle \f(CW'World '\fR ne trouve pas de correspondance car il y a un espace a\*` la fin de l'expression rationnelle et non a\*` la fin de la chai\*^ne. La lec\*,on a tirer de ces exemples est qu'une expression rationnelle doit correspondre \&\fIexactement\fR a\*` une partie de la chai\*^ne pour e\*^tre reconnue. .PP Si une expression rationnelle peut e\*^tre reconnue a\*` plusieurs endroits dans une chai\*^ne, perl choisira toujours la correspondance au plus to\*^t\ : .PP .Vb 2 \& "Hello World" =~ /o/; # correspond au 'o' dans 'Hello' \& "That hat is red" =~ /hat/; # correspond au 'hat' dans 'That' .Ve .PP Il y a encore quelques points que vous devez savoir a\*` propos de la reconnaissance de caracte\*`res. En premier lieu, tous les caracte\*`res ne peuvent pas e\*^tre utilise\*'s tels quels pour une correspondance. Quelques caracte\*`res, appele\*'s \fBmeta\-caracte\*`res\fR, sont re\*'serve\*'s pour des notations d'expressions rationnelles. Les meta\-caracte\*`res sont\ : .PP .Vb 1 \& {}[]()^$.|*+?\e .Ve .PP La signification de chacun d'eux sera explique\*'e plus loin dans ce tutoriel. Pour l'heure, il vous suffira de savoir qu'un meta\-caracte\*`re sera recherche\*' tel quel si vous le pre\*'ce\*'dez d'un backslash (une barre oblique inverse\*'e)\ : .PP .Vb 5 \& "2+2=4" =~ /2+2/; # pas de correspondance, + est un meta\-caracte\*`re \& "2+2=4" =~ /2\e+2/; # correspond, \e+ est traite\*' comme un + ordinaire \& "The interval is [0,1)." =~ /[0,1)./ # c'est une erreur de syntaxe ! \& "The interval is [0,1)." =~ /\e[0,1\e)\e./ # correspond \& "/usr/bin/perl" =~ /\e/usr\e/bin\e/perl/; # correspond .Ve .PP Dans la dernie\*`re expression rationnelle, les slash \f(CW'/'\fR sont aussi pre\*'ce\*'de\*'s d'un backslash parce que le slash est utilise\*' comme de\*'limiteur de l'expression rationnelle. Par contre, cela peut aboutir au \s-1LTS\s0 (leaning toothpick syndrome) et il est donc souvent pre\*'fe\*'rable de changer de de\*'limiteur. .PP .Vb 1 \& "/usr/bin/perl" =~ m!/usr/bin/perl!; # plus facile a\*` lire .Ve .PP Le caracte\*`re backslash \f(CW'\e'\fR est lui\-me\*^me un meta\-caracte\*`re et doit donc e\*^tre backslashe\*' (pre\*'ce\*'de\*' d'un backslash)\ : .PP .Vb 1 \& 'C:\eWIN32' =~ /C:\e\eWIN/; # correspond .Ve .PP En plus des meta\-caracte\*`res, il y a quelques caracte\*`res \s-1ASCII\s0 qui n'ont pas d'e\*'quivalent affichable et sont donc repre\*'sente\*'s par des \&\fBse\*'quences d'e\*'chappement\fR. Les plus courants sont \f(CW\*(C`\et\*(C'\fR pour une tabulation, \f(CW\*(C`\en\*(C'\fR pour un saut de ligne, \f(CW\*(C`\er\*(C'\fR pour un retour chariot et \f(CW\*(C`\ea\*(C'\fR pour un beep. Si votre chai\*^ne se pre\*'sente pluto\*^t comme une se\*'quence d'octets quelconques, les se\*'quences d'e\*'chappement en octal, tel que \f(CW\*(C`\e033\*(C'\fR, ou en hexade\*'cimal, tel que \f(CW\*(C`\ex1B\*(C'\fR seront peut\-e\*^tre une repre\*'sentation plus naturelle pour vos octets. Voici quelques exemples d'utilisation des se\*'quences d'e\*'chappement\ : .PP .Vb 4 \& "1000\et2000" =~ m(0\et2) # correspond \& "1000\en2000" =~ /0\en20/ # correspond \& "1000\et2000" =~ /\e000\et2/ # ne correspond pas, "0" ne "\e000" \& "cat" =~ /\e143\ex61\ex74/ # correspond, une fac\*,on bizarre d'e\*'peler 'cat' .Ve .PP Si vous pratiquez de\*'ja\*` Perl, tout cela doit vous semblez familier. Des se\*'quences similaires sont utilise\*'es dans les chai\*^nes entre guillemets. De fait, les expressions rationnelles en Perl sont traite\*'es comme des chai\*^nes entre guillemets. Cela signifie que l'on peut utiliser des variables dans les expressions rationnelles. Exactement comme pour les chai\*^nes entre guillemets, chaque variable sera remplace\*'e par sa valeur avant que l'expression rationnelle soit utilise\*'e a\*` la recherche de correspondances. Donc\ : .PP .Vb 4 \& $foo = 'house'; \& 'housecat' =~ /$foo/; # correspond \& 'cathouse' =~ /cat$foo/; # correspond \& 'housecat' =~ /${foo}cat/; # correspond .Ve .PP Jusqu'ici, c\*,a va. Avec les connaissances qui pre\*'ce\*`dent vous pouvez de\*'ja\*` rechercher toutes les chai\*^nes litte\*'rales imaginables. Voici une e\*'mulation \fItre\*`s simple\fR du programme Unix grep\ : .PP .Vb 7 \& % cat > simple_grep \& #!/usr/bin/perl \& $regexp = shift; \& while (<>) { \& print if /$regexp/; \& } \& ^D \& \& % chmod +x simple_grep \& \& % simple_grep abba /usr/dict/words \& Babbage \& cabbage \& cabbages \& sabbath \& Sabbathize \& Sabbathizes \& sabbatical \& scabbard \& scabbards .Ve .PP Ce programme est tre\*`s simple a\*` comprendre. \f(CW\*(C`#!/usr/bin/perl\*(C'\fR est le moyen standard pour invoquer perl. \f(CW\*(C`$regexp\ =\ shift;\*(C'\fR me\*'morise le premier argument de la ligne de commande en tant qu'expression rationnelle a\*` utiliser et laisse le reste des arguments pour qu'ils soient traiter comme des fichiers. \f(CW\*(C`while\ (<>)\*(C'\fR\ parcourt toutes les lignes de tous les fichiers. Pour chaque ligne, \f(CW\*(C`print\ if\ /$regexp/;\*(C'\fR\ affiche la ligne si l'expression rationnelle trouve une correspondance dans la ligne. Dans cette ligne, \f(CW\*(C`print\*(C'\fR et \&\f(CW\*(C`/$regexp/\*(C'\fR utilisent implicitement tous les deux la variable par de\*'faut \f(CW$_\fR. .PP Dans toutes les expressions rationnelles pre\*'ce\*'dentes, si l'expression rationnelle trouvait une correspondance n'importe ou\*` dans la chai\*^ne, on conside\*'rait qu'elle correspondait. Parfois, par contre, nous aimerions spe\*'cifier \fIl'endroit\fR dans la chai\*^ne ou\*` l'expression rationnelle doit trouver une correspondance. Pour cela, nous devons utiliser les meta\-caracte\*`res d'ancrage \f(CW\*(C`^\*(C'\fR et \f(CW\*(C`$\*(C'\fR. L'ancre \f(CW\*(C`^\*(C'\fR demande a\*` correspondre au de\*'but de la chai\*^ne et l'ancre \f(CW\*(C`$\*(C'\fR demande a\*` correspondre a\*` la fin de la chai\*^ne ou juste avant le passage a\*` la ligne avant la fin de la chai\*^ne. Voici comment elles sont utilise\*'es\ : .PP .Vb 4 \& "housekeeper" =~ /keeper/; # correspond \& "housekeeper" =~ /^keeper/; # ne correspond pas \& "housekeeper" =~ /keeper$/; # correspond \& "housekeeper\en" =~ /keeper$/; # correspond .Ve .PP La deuxie\*`me expression rationnelle ne correspond pas parce que \f(CW\*(C`^\*(C'\fR contraint \f(CW\*(C`keeper\*(C'\fR a\*` ne correspondre qu'au de\*'but de la chai\*^ne. Or \&\f(CW"housekeeper"\fR contient un \*(L"keeper\*(R" qui de\*'bute au milieu de la chai\*^ne. La troisie\*`me expression rationnelle correspond puisque le \f(CW\*(C`$\*(C'\fR contraint \f(CW\*(C`keeper\*(C'\fR a\*` n'e\*^tre reconnue qu'a\*` la fin de la chai\*^ne. .PP Lorsque \f(CW\*(C`^\*(C'\fR et \f(CW\*(C`$\*(C'\fR sont utilise\*'s ensemble, l'expression rationnelle doit e\*^tre ancre\*'e a\*` la fois au de\*'but et a\*` la fin de la chai\*^ne, i.e., l'expression rationnelle correspond donc a\*` la chai\*^ne entie\*`re. Conside\*'rons\ : .PP .Vb 3 \& "keeper" =~ /^keep$/; # ne correspond pas \& "keeper" =~ /^keeper$/; # correspond \& "" =~ /^$/; # ^$ correspond a\*` la chai\*^ne vide .Ve .PP La premie\*`re expression rationnelle ne peut pas correspondre puisque la chai\*^ne contient plus que \f(CW\*(C`keep\*(C'\fR. Puisque la deuxie\*`me expression rationnelle est exactement la chai\*^ne, elle correspond. L'utilisation combine\*'e de \f(CW\*(C`^\*(C'\fR et de \f(CW\*(C`$\*(C'\fR force la chai\*^ne entie\*`re a\*` correspondre et vous donne donc un contro\*^le complet sur les chai\*^nes qui correspondent et celles qui ne correspondent pas. Supposons que vous cherchez un individu nomme\*' bert\ : .PP .Vb 1 \& "dogbert" =~ /bert/; # correspond, mais ce n'est pas ce qu'on cherche \& \& "dilbert" =~ /^bert/; # ne correspond pas mais... \& "bertram" =~ /^bert/; # correspond, ce n'est donc pas encore bon \& \& "bertram" =~ /^bert$/; # ne correspond pas, ok \& "dilbert" =~ /^bert$/; # ne correspond pas, ok \& "bert" =~ /^bert$/; # correspond, parfait .Ve .PP Bien su\*^r, dans le cas d'une chai\*^ne litte\*'rale, n'importe qui utiliserait l'ope\*'rateur d'e\*'galite\*' des chai\*^nes \f(CW\*(C`$string\ eq\ 'bert'\*(C'\fR\ et cela serait beaucoup plus efficient. L'expression rationnelle \&\f(CW\*(C`^...$\*(C'\fR devient beaucoup plus pratique lorsqu'on lui ajoute la puissance des outils d'expression rationnelle que nous verrons plus bas. .Sh "Utilisation des classes de caracte\*`res" .IX Subsection "Utilisation des classes de caracte`res" Bien que certains puissent se satisfaire des expressions rationnelles pre\*'ce\*'dentes qui ne reconnaissent que des chai\*^nes litte\*'rales, nous n'avons qu'effleure\*' la technologie des expressions rationnelles. Dans cette section et les suivantes nous allons pre\*'senter les concepts d'expressions rationnelles (et les meta\-caracte\*`res associe\*'s) qui permettent a\*` une expression rationnelle de repre\*'senter non seulement une seule se\*'quence de caracte\*`res mais aussi \fItoute une classe\fR de se\*'quences. .PP L'un de ces concepts et celui de \fBclasse de caracte\*`res\fR. Une classe de caracte\*`res autorise un ensemble de caracte\*`res, pluto\*^t qu'un seul caracte\*`re, a\*` correspondre en un point particulier de l'expression rationnelle. Les classes de caracte\*`res sont entoure\*'es de crochets \&\f(CW\*(C`[...]\*(C'\fR avec l'ensemble de caracte\*`res place\*' a\*` l'inte\*'rieur. Voici quelques exemples\ : .PP .Vb 4 \& /cat/; # reconnai\*^t 'cat' \& /[bcr]at/; # reconnai\*^t 'bat, 'cat', ou 'rat' \& /item[0123456789]/; # reconnai\*^t 'item0' ou ... ou 'item9' \& "abc" =~ /[cab]/; # reconnai\*^t le 'a' .Ve .PP Dans la dernie\*`re instruction, bien que \f(CW'c'\fR soit le premier caracte\*`re dans la classe, c'est le \f(CW'a'\fR qui correspond car c'est le caracte\*`re le plus au de\*'but de la chai\*^ne avec lequel l'expression rationnelle peut correspondre. .PP .Vb 2 \& /[oO][uU][iI]/; # reconnai\*^t 'oui' sans tenir compte de la casse \& # 'oui', 'Oui, 'OUI', etc. .Ve .PP Cette expression rationnelle re\*'alise une ta\*^che courante\ : une recherche de correspondance insensible a\*` la casse. Perl fournit un moyen d'e\*'viter tous ces crochets en ajoutant simplement un \f(CW'i'\fR apre\*`s l'expression rationnelle. Donc \f(CW\*(C`/[oO][uU][iI]/;\*(C'\fR peut e\*^tre re\*'e\*'crit en \f(CW\*(C`/oui/i;\*(C'\fR. Le \f(CW'i'\fR signifie insensible a\*` la casse et est un exemple de \fBmodificateur\fR de l'ope\*'ration de reconnaissance. Nous rencontrerons d'autres modificateurs plus tard dans ce tutoriel. .PP Nous avons vu dans la section pre\*'ce\*'dente qu'il y avait des caracte\*`res ordinaires, qui se repre\*'sentaient eux\-me\*^mes et des caracte\*`res spe\*'ciaux qui devaient e\*^tre backslashe\*'s pour se repre\*'senter. C'est la me\*^me chose dans les classes de caracte\*`res mais les ensembles de caracte\*`res ordinaires et spe\*'ciaux ne sont pas les me\*^mes. Les caracte\*`res spe\*'ciaux dans une classe de caracte\*`res sont \f(CW\*(C`\-]\e^$\*(C'\fR. \f(CW\*(C`]\*(C'\fR est spe\*'cial car il indique la fin de la classe de caracte\*`res. \f(CW\*(C`$\*(C'\fR est spe\*'cial car il indique une variable scalaire. \f(CW\*(C`\e\*(C'\fR est spe\*'cial car il est utilise\*' pour les se\*'quences d'e\*'chappement comme pre\*'ce\*'demment. Voici comment les caracte\*`res spe\*'ciaux \f(CW\*(C`]$\e\*(C'\fR sont utilise\*'s\ : .PP .Vb 5 \& /[\e]c]def/; # reconnai\*^t ']def' ou 'cdef' \& $x = 'bcr'; \& /[$x]at/; # reconnai\*^t 'bat', 'cat', ou 'rat' \& /[\e$x]at/; # reconnai\*^t '$at' ou 'xat' \& /[\e\e$x]at/; # reconnai\*^t '\eat', 'bat, 'cat', ou 'rat' .Ve .PP Les deux derniers exemples sont un peu complexes. Dans \f(CW\*(C`[\e$x]\*(C'\fR, le backslash prote\*`ge le signe dollar et donc la classe de caracte\*`res contient deux membres : \f(CW\*(C`$\*(C'\fR et \f(CW\*(C`x\*(C'\fR. Dans \f(CW\*(C`[\e\e$x]\*(C'\fR, le backslash est lui\-me\*^me prote\*'ge\*' et donc \f(CW$x\fR est traite\*' comme une variable a\*` laquelle on substitue sa valeur comme dans les chai\*^nes entre guillemets. .PP Le caracte\*`re spe\*'cial \f(CW'\-'\fR agit comme un ope\*'rateur d'intervalle dans une classe de caracte\*`res et donc un ensemble de caracte\*`res contigus peut e\*^tre de\*'crit comme un intervalle. Gra\*^ce aux intervalles, les classes peu maniables comme \f(CW\*(C`[0123456789]\*(C'\fR et \f(CW\*(C`[abc...xyz]\*(C'\fR deviennent tre\*`s simples\ : \f(CW\*(C`[0\-9]\*(C'\fR et \f(CW\*(C`[a\-z]\*(C'\fR. Quelques exemples\ : .PP .Vb 6 \& /item[0\-9]/; # reconnai\*^t 'item0' ou ... ou 'item9' \& /[0\-9bx\-z]aa/; # reconnai\*^t '0aa', ..., '9aa', \& # 'baa', 'xaa', 'yaa', or 'zaa' \& /[0\-9a\-fA\-F]/; # reconnai\*^t un chiffre hexade\*'cimal \& /[0\-9a\-zA\-Z_]/; # reconnai\*^t un caracte\*`re d'un "mot", \& # comme ceux qui composent les noms en Perl .Ve .PP Si \f(CW'\-'\fR est le premier ou le dernier des caracte\*`res dans une classe, il est traite\*' comme un caracte\*`re ordinaire ; \f(CW\*(C`[\-ab]\*(C'\fR, \f(CW\*(C`[ab\-]\*(C'\fR et \&\f(CW\*(C`[a\e\-b]\*(C'\fR sont e\*'quivalents. .PP Le caracte\*`re spe\*'cial \f(CW\*(C`^\*(C'\fR en premie\*`re position d'une classe de caracte\*`res indique une \fBclasse de caracte\*`res inverse\fR qui reconnai\*^t n'importe quel caracte\*`re sauf ceux pre\*'sents entre les crochets. Dans les deux cas, \f(CW\*(C`[...]\*(C'\fR et \f(CW\*(C`[^...]\*(C'\fR, il faut qu'un caracte\*`re soit reconnu sinon la reconnaissance e\*'choue. Donc\ : .PP .Vb 4 \& /[^a]at/; # ne reconnai\*^t pas 'aat' ou 'at', mais reconnai\*^t \& # tous les autres 'bat', 'cat, '0at', '%at', etc. \& /[^0\-9]/; # reconnai\*^t un caracte\*`re non nume\*'rique \& /[a^]at/; # reconnai\*^t 'aat' or '^at'; ici '^' est ordinaire .Ve .PP Me\*^me \f(CW\*(C`[0\-9]\*(C'\fR peut e\*^tre ennuyeux a\*` e\*'crire plusieurs fois. Donc pour minimiser la frappe et rendre les expressions rationnelles plus lisibles, Perl propose plusieurs abre\*'viations pour les classes les plus communes\ : .IP "\(bu" 4 \&\ed est un chiffre et repre\*'sente [0\-9] .IP "\(bu" 4 \&\es est un caracte\*`re d'espacement et repre\*'sente [\e \et\er\en\ef] .IP "\(bu" 4 \&\ew est un caracte\*`re de mot (alphanume\*'rique ou _) et repre\*'sente [0\-9a\-zA\-Z_] .IP "\(bu" 4 \&\eD est la ne\*'gation de \ed; il repre\*'sente n'importe quel caracte\*`re sauf un chiffre [^0\-9] .IP "\(bu" 4 \&\eS est la ne\*'gation de \es; il repre\*'sente n'importe quel caracte\*`re qui ne soit pas d'espacement [^\es] .IP "\(bu" 4 \&\eW est la ne\*'gation de \ew; il repre\*'sente n'importe quel caracte\*`re qui ne soit un pas un caracte\*`re de mot [^\ew] .IP "\(bu" 4 Le point '.' reconnai\*^t n'importe quel caracte\*`re sauf \*(L"\en\*(R" .PP Les abre\*'viations \f(CW\*(C`\ed\es\ew\eD\eS\eW\*(C'\fR peuvent e\*^tre utilise\*'es a\*` l'inte\*'rieur ou a\*` l'exte\*'rieur des classes de caracte\*`res. Voici quelques exemples\ : .PP .Vb 7 \& /\ed\ed:\ed\ed:\ed\ed/; # reconnai\*^t une heur au format hh:mm:ss \& /[\ed\es]/; # reconnai\*^t n'importe quel chiffre ou espacement \& /\ew\eW\ew/; # reconnai\*^t un caracte\*`re mot, suivi d'un \& # caracte\*`re non\-mot, suivi d'un caracte\*`re mot \& /..rt/; # reconnai\*^t deux caracte\*`re, suivis de 'rt' \& /end\e./; # reconnai\*^t 'end.' \& /end[.]/; # la me\*^me chose, reconnai\*^t 'end.' .Ve .PP Puisque un point est un meta\-caracte\*`re, il doit e\*^tre backslashe\*' pour reconnai\*^tre un point ordinaire. Puisque, par exemple, \f(CW\*(C`\ed\*(C'\fR et \f(CW\*(C`\ew\*(C'\fR sont des ensembles de caracte\*`res, il est incorrect de penser que \&\f(CW\*(C`[^\ed\ew]\*(C'\fR est e\*'quivalent a\*` \f(CW\*(C`[\eD\eW]\*(C'\fR; en fait \f(CW\*(C`[^\ed\ew]\*(C'\fR est la me\*^me chose que \f(CW\*(C`[^\ew]\*(C'\fR, qui est la me\*^me chose que \f(CW\*(C`[\eW]\*(C'\fR. C'est l'application des lois ensemblistes de De Morgan. .PP Une ancre pratique dans les expressions rationnelles de base est \&\fBl'ancre de mot\fR \f(CW\*(C`\eb\*(C'\fR. Elle reconnai\*^t la frontie\*`re entre un caracte\*`re mot et un caracte\*`re non-mot \f(CW\*(C`\ew\eW\*(C'\fR ou \f(CW\*(C`\eW\ew\*(C'\fR\ : .PP .Vb 5 \& $x = "Housecat catenates house and cat"; \& $x =~ /cat/; # reconnai\*^t cat dans 'housecat' \& $x =~ /\ebcat/; # reconnai\*^t cat dans 'catenates' \& $x =~ /cat\eb/; # reconnai\*^t cat dans 'housecat' \& $x =~ /\ebcat\eb/; # reconnai\*^t 'cat' a\*` la fin de la chai\*^ne .Ve .PP Notez que dans le dernier exemple, la fin de la chai\*^ne est conside\*'re\*'e comme une frontie\*`re de mot. .PP Vous devez vous demander pourquoi \f(CW'.'\fR reconnai\*^t tous les caracte\*`res sauf \f(CW"\en"\fR \- pourquoi pas tous les caracte\*`res ? C'est parce que le plus souvent on effectue des mises en correspondance par ligne et que nous voulons ignorer le caracte\*`re de passage a\*` la ligne. Par exemple, bien que la chai\*^ne \f(CW"\en"\fR repre\*'sente une ligne, nous aimons la conside\*'rer comme vide. Par conse\*'quent\ : .PP .Vb 2 \& "" =~ /^$/; # est reconnue \& "\en" =~ /^$/; # est reconnue; "\en" est ignore\*' \& \& "" =~ /./; # n'est pas reconnue; ne\*'cessite un caracte\*`re \& "" =~ /^.$/; # n'est pas reconnue; ne\*'cessite un caracte\*`re \& "\en" =~ /^.$/; # n'est pas reconnue; ne\*'cessite un caracte\*`re autre que "\en" \& "a" =~ /^.$/; # est reconnue \& "a\en" =~ /^.$/; # est reconnue; "\en" est ignore\*' .Ve .PP Ce comportement est pratique parce qu'habituellement nous voulons ignorer les passages a\*` la ligne lorsque nous mettons en correspondance les caracte\*`res d'une ligne. Parfois, en revanche, nous voulons tenir compte des passages a\*` la ligne. Nous pouvons aussi vouloir que les ancres \f(CW\*(C`^\*(C'\fR et \f(CW\*(C`$\*(C'\fR puissent s'ancrer au de\*'but et a\*` la fin des lignes pluto\*^t que simplement au de\*'but et a\*` la fin de la chai\*^ne. Perl nous permet de choisir entre ignorer ou tenir compte des passages a\*` la ligne gra\*^ce aux modificateurs \f(CW\*(C`//s\*(C'\fR et \f(CW\*(C`//m\*(C'\fR. \f(CW\*(C`//s\*(C'\fR et \f(CW\*(C`//m\*(C'\fR signifient ligne simple et multi-ligne et ils de\*'terminent si une chai\*^ne doit e\*^tre conside\*'re\*'e comme une chai\*^ne continue ou comme un ensemble de lignes. Les deux modificateurs agissent sur deux aspects de l'interpre\*'tation de l'expression rationnelle\ : 1) comment la classe de caracte\*`res \f(CW'.'\fR est de\*'finie et 2) ou\*` les ancres \f(CW\*(C`^\*(C'\fR et \&\f(CW\*(C`$\*(C'\fR peuvent s'ancrer. Voici les quatre combinaisons\ : .IP "\(bu" 4 pas de modificateurs (//)\ : comportement par de\*'faut. \f(CW'.'\fR reconnai\*^t n'importe quel caracte\*`re sauf \f(CW"\en"\fR. \f(CW\*(C`^\*(C'\fR correspond uniquement au de\*'but de la chai\*^ne et \f(CW\*(C`$\*(C'\fR correspond uniquement a\*` la fin de la chai\*^ne ou avant le passage a\*` la ligne avant la fin de la chai\*^ne. .IP "\(bu" 4 modificateur s (//s)\ : traite la chai\*^ne comme une seule longue ligne. \f(CW'.'\fR reconnai\*^t tous les caracte\*`res, me\*^me \f(CW"\en"\fR. \f(CW\*(C`^\*(C'\fR correspond uniquement au de\*'but de la chai\*^ne et \f(CW\*(C`$\*(C'\fR correspond uniquement a\*` la fin de la chai\*^ne ou avant le passage a\*` la ligne avant la fin de la chai\*^ne. .IP "\(bu" 4 modificateur m (//m)\ : traite la chai\*^ne comme un ensemble de lignes. \f(CW'.'\fR reconnai\*^t n'importe quel caracte\*`re sauf \f(CW"\en"\fR. \f(CW\*(C`^\*(C'\fR et \f(CW\*(C`$\*(C'\fR peuvent correspondre au de\*'but et a\*` la fin de n'importe quelle ligne dans la chai\*^ne. .IP "\(bu" 4 les deux modificateurs s et m (//sm)\ : traite la chai\*^ne comme une seule longue ligne mais de\*'tecte les lignes multiples. \f(CW'.'\fR reconnai\*^t tous les caracte\*`res, me\*^me \f(CW"\en"\fR. \f(CW\*(C`^\*(C'\fR et \f(CW\*(C`$\*(C'\fR peuvent correspondre au de\*'but et a\*` la fin de n'importe quelle ligne dans la chai\*^ne. .PP Voici des exemples d'utilisation de \f(CW\*(C`//s\*(C'\fR et \f(CW\*(C`//m\*(C'\fR\ : .PP .Vb 1 \& $x = "There once was a girl\enWho programmed in Perl\en"; \& \& $x =~ /^Who/; # non reconnue, "Who" n'est pas en de\*'but de chai\*^ne \& $x =~ /^Who/s; # non reconnue, "Who" n'est pas en de\*'but de chai\*^ne \& $x =~ /^Who/m; # reconnue, "Who" au de\*'but de la seconde ligne \& $x =~ /^Who/sm; # reconnue, "Who" au de\*'but de la seconde ligne \& \& $x =~ /girl.Who/; # non reconnue, le "." ne reconnai\*^t pas "\en" \& $x =~ /girl.Who/s; # reconnue, le "." reconnai\*^t "\en" \& $x =~ /girl.Who/m; # non reconnue, le "." ne reconnai\*^t pas "\en" \& $x =~ /girl.Who/sm; # reconnue, le "." reconnai\*^t "\en" .Ve .PP La plupart du temps, le comportement par de\*'faut est ce que nous voulons mais \&\f(CW\*(C`//s\*(C'\fR et \f(CW\*(C`//m\*(C'\fR sont occasionnellement tre\*`s utiles. Si \f(CW\*(C`//m\*(C'\fR est utilise\*', le de\*'but de la chai\*^ne peut encore e\*^tre reconnu par \f(CW\*(C`\eA\*(C'\fR et la fin de la chai\*^ne peut aussi e\*^tre reconnue soit par l'ancre \f(CW\*(C`\eZ\*(C'\fR (qui est reconnue a\*` la fin de la chai\*^ne ou juste avant le passage a\*` la ligne, comme \f(CW\*(C`$\*(C'\fR) soit par l'ancre \&\f(CW\*(C`\ez\*(C'\fR (qui n'est reconnue qu'a\*` la fin de la chai\*^ne)\ : .PP .Vb 2 \& $x =~ /^Who/m; # reconnue, "Who" au de\*'but de la seconde ligne \& $x =~ /\eAWho/m; # non reconnue, "Who" n'est pas au de\*'but de la chai\*^ne \& \& $x =~ /girl$/m; # reconnue, "girl" a\*` la fin de la premie\*`re ligne \& $x =~ /girl\eZ/m; # non reconnue, "girl" n'est pas a\*` la fin de la chai\*^ne \& \& $x =~ /Perl\eZ/m; # reconnue, "Perl" est juste avant le passage a\*` la ligne \& # de la fin de chai\*^ne \& $x =~ /Perl\ez/m; # non reconnue, "Perl" n'est pas a\*` la fin de la chai\*^ne .Ve .PP Nous savons maintenant comment cre\*'er des choix a\*` travers des classes de caracte\*`res dans les expressions rationnelles. Qu'en est-il de choix entre des mots ou des chai\*^nes de caracte\*`res ? Ce sont ces choix qui sont de\*'crits dans la section suivante. .Sh "Reconnai\*^tre ceci ou cela" .IX Subsection "Reconnai^tre ceci ou cela" Parfois nous aimerions que notre expression rationnelle soit capable de reconnai\*^tre diffe\*'rents mots ou suites de caracte\*`res. Ceci s'effectue en utilisant le meta\-caracte\*`re d'alternative \f(CW\*(C`|\*(C'\fR. Pour reconnai\*^tre \f(CW\*(C`dog\*(C'\fR ou \&\f(CW\*(C`cat\*(C'\fR, nous formons l'expression rationnelle \f(CW\*(C`dog|cat\*(C'\fR. Comme pre\*'ce\*'demment, perl essaie de reconnai\*^tre l'expression rationnelle le plus to\*^t possible dans la chai\*^ne. A\*` chaque position, perl essaie en premier de reconnai\*^tre la premie\*`re branche de l'alternative, \f(CW\*(C`dog\*(C'\fR. Si \f(CW\*(C`dog\*(C'\fR n'est pas reconnu, perl essaie ensuite la branche suivante, \f(CW\*(C`cat\*(C'\fR. Si \f(CW\*(C`cat\*(C'\fR n'est pas reconnu non plus alors la mise en correspondance e\*'choue et perl se de\*'place a\*` la position suivante dans la chai\*^ne. Quelques exemples\ : .PP .Vb 2 \& "cats and dogs" =~ /cat|dog|bird/; # reconnai\*^t "cat" \& "cats and dogs" =~ /dog|cat|bird/; # reconnai\*^t "cat" .Ve .PP Me\*^me si \f(CW\*(C`dog\*(C'\fR est la premie\*`re branche de l'alternative dans le second exemple, \f(CW\*(C`cat\*(C'\fR est reconnu plus to\*^t dans la chai\*^ne. .PP .Vb 2 \& "cats" =~ /c|ca|cat|cats/; # reconnai\*^t "c" \& "cats" =~ /cats|cat|ca|c/; # reconnai\*^t "cats" .Ve .PP Ici, toutes les branches peuvent correspondre a\*` la premie\*`re position dont la premie\*`re branche reconnue est celle qui est retenue. Si certaines branches de l'alternative sont des troncatures des autres, placez les plus longues en premier pour leur donner une chance d'e\*^tre reconnues. .PP .Vb 2 \& "cab" =~ /a|b|c/ # reconnai\*^t "c" \& # /a|b|c/ == /[abc]/ .Ve .PP Ce dernier exemple montre que les classes de caracte\*`res sont comme des alternatives entre caracte\*`res. A\*` une position donne\*'e, la premie\*`re branche qui permet une mise en correspondance de l'expression rationnelle est celle qui sera reconnue. .Sh "Regroupement et reconnaissance hie\*'rarchique" .IX Subsection "Regroupement et reconnaissance hie'rarchique" Les alternatives permettent a\*` une expression rationnelle de choisir entre diffe\*'rentes branches mais elles restent non satisfaisantes en elles\-me\*^mes. Pour la simple raison que l'alternative est une expression rationnelle comple\*`te alors que parfois nous aimerions que ce ne soit qu'une partie de l'expression rationnelle. Par exemple, supposons que nous voulions reconnai\*^tre housecat ou housekeeper. L'expression rationnelle \f(CW\*(C`housecat|housekeeper\*(C'\fR fonctionne mais est inefficace puisque nous avons du taper \f(CW\*(C`house\*(C'\fR deux fois. Il serait pratique d'avoir une partie de l'expression rationnelle qui soit constante, comme \f(CW\*(C`house\*(C'\fR, et une partie qui soit une alternative, comme \f(CW\*(C`cat|keeper\*(C'\fR. .PP Les meta\-caracte\*`res de \fBregroupement\fR \f(CW\*(C`()\*(C'\fR re\*'solvent ce proble\*`me. Le regroupement permet a\*` une partie d'une expression rationnelle d'e\*^tre traiter comme une seule entite\*'. Une partie d'une expression rationnelle est regroupe\*'e en la plac\*,ant entre des parenthe\*`ses. Donc nous pouvons re\*'soudre le proble\*`me \&\f(CW\*(C`housecat|housekeeper\*(C'\fR en formant l'expression rationnelle \&\f(CW\*(C`house(cat|keeper)\*(C'\fR. L'expression rationnelle \f(CW\*(C`house(cat|keeper)\*(C'\fR signifie cherche \f(CW\*(C`house\*(C'\fR suivi soit par \f(CW\*(C`cat\*(C'\fR soit par \f(CW\*(C`keeper\*(C'\fR. Quelques exemples\ : .PP .Vb 4 \& /(a|b)b/; # reconnai\*^t 'ab' ou 'bb' \& /(ac|b)b/; # reconnai\*^t 'acb' ou 'bb' \& /(^a|b)c/; # reconnai\*^t 'ac' au de\*'but de la chai\*^ne ou 'bc' n'importe ou\*` \& /(a|[bc])d/; # reconnai\*^t 'ad', 'bd', ou 'cd' \& \& /house(cat|)/; # reconnai\*^t soit 'housecat' soit 'house' \& /house(cat(s|)|)/; # reconnai\*^t soit 'housecats' soit 'housecat' soit \& # 'house'. Les groupes peuvent e\*^tre imbrique\*'s. \& \& /(19|20|)\ed\ed/; # reconnai\*^t les anne\*'es 19xx, 20xx, ou xx \& "20" =~ /(19|20|)\ed\ed/; # reconnai\*^t la branche vide '()\ed\ed', \& # puisque '20\ed\ed' ne peut pas correspondre .Ve .PP Les alternatives se comportent de la me\*^me manie\*`re, qu'elles soient dans ou hors d'un groupe\ : a\*` une position donne\*'e, c'est la branche la plus a\*` gauche qui est choisie tant qu'elle permet la reconnaissance de l'expression rationnelle. Donc dans notre dernier exemple, a\*` la premie\*`re position de la chai\*^ne, \f(CW"20"\fR est reconnu par la deuxie\*`me branche de l'alternative mais il ne reste rien pour e\*^tre reconnu par les deux chiffres suivants \f(CW\*(C`\ed\ed\*(C'\fR. Alors perl essaie la branche suivante qui est la branche vide et c\*,a marche puisque \&\f(CW"20"\fR est compose\*' de deux chiffres. .PP Le processus d'essai d'une branche pour voir si elle convient puis d'une autre sinon est appele\*' \fBretour arrie\*`re\fR (\fBbacktracking\fR en anglais). Les termes \&'retour arrie\*`re' viennent de l'ide\*'e que la reconnaissance d'une expression rationnelle est comme une marche en fore\*^t. La reconnaissance de l'expression rationnelle est comme l'arrive\*'e a\*` destination. Il y a plusieurs points de de\*'part possibles, un pour chaque position dans la chai\*^ne et chacun d'eux est essaye\*' dans l'ordre, de gauche a\*` droite. A\*` partir de chaque point de de\*'part, il y a plusieurs chemins dont certains sont des impasses et d'autres vous ame\*`nent a\*` destination. Lorsque vous marchez sur un chemin et qu'il aboutit a\*` une impasse, vous devez retourner en arrie\*`re pour essayer un autre chemin. Vous e\*^tes perse\*'ve\*'rant et vous ne vous de\*'clarez vaincu que lorsque vous avez essaye\*' tous les chemins a\*` partir de tous les points de de\*'part sans aboutir a\*` destination. Pour e\*^tre plus concret, voici une analyse pas a\*` pas de ce que perl fait lorsqu'il essaye de reconnai\*^tre l'expression rationnelle\ : .PP .Vb 1 \& "abcde" =~ /(abd|abc)(df|d|de)/; .Ve .IP "1." 4 On de\*'marre avec la premie\*`re lettre de la chai\*^ne 'a'. .IP "2." 4 On essaie la premie\*`re branche de la premie\*`re alternative, le groupe 'abd'. .IP "3." 4 On reconnai\*^t un 'a' suivi d'un 'b'. Jusqu'ici, c\*,a va. .IP "4." 4 \&'d' dans l'expression rationnelle ne correspond pas au 'c' dans la chai\*^ne \- une impasse. On effectue alors un retour arrie\*`re de deux caracte\*`res et on essaie la seconde branche de la premie\*`re alternative, le groupe 'abc'. .IP "5." 4 On reconnai\*^t un 'a' suivi d'un 'b' suivi d'un 'c'. Nous avons donc satisfait le premier regroupement. On positionne \f(CW$1\fR a\*` 'abc'. .IP "6." 4 On continue avec la seconde alternative et on choisit la premie\*`re branche \&'df'. .IP "7." 4 On reconnai\*^t le 'd'. .IP "8." 4 \&'f' dans l'expression rationnelle ne correspond pas au 'e' dans la chai\*^ne; c'est donc une impasse. Retour arrie\*`re d'un caracte\*`re et choix de la seconde branche de la seconde alternative 'd'. .IP "9." 4 \&'d' est reconnu. Le second regroupement est satisfait et on positionne \f(CW$2\fR a\*` \&'d'. .IP "10." 4 Nous sommes a\*` la fin de l'expression rationnelle. Nous sommes donc arrive\*'s a\*` destination ! Nous avons reconnu 'abcd' dans la chai\*^ne \*(L"abcde\*(R". .PP Il y a deux choses a\*` dire sur cette analyse. Tout d'abord, la troisie\*`me alternative ('de') dans le second regroupement permet aussi une reconnaissance, mais nous nous sommes arre\*^te\*'s avant d'y arriver \- a\*` une position donne\*'e, l'alternative la plus a\*` gauche l'emporte. Ensuite, nous avons obtenu une reconnaissance au premier caracte\*`re ('a') de la chai\*^ne. Si la reconnaissance n'avait pas e\*'te\*' possible a\*` cette premie\*`re position, perl se serait de\*'placer a\*` la deuxie\*`me position ('b') pour essayer a\*` nouveau une reconnaissance comple\*`te. C'est uniquement lorsque tous les chemins et toutes les positions ont e\*'te\*' essaye\*'s sans succe\*`s que perl s'arre\*^te et de\*'clare fausse l'assertion \f(CW\*(C`$string\ =~\ /(abd|abc)(df|d|de)/;\*(C'\fR\ . .PP Me\*^me avec tout ce boulot, les expressions rationnelles restent remarquablement rapides. Pour ame\*'liorer cela, durant la phase de compilation, perl compile les expressions rationnelles en une se\*'quence compacte de opcodes qui peut parfois tenir dans le cache du processeur. Lorsque le code est exe\*'cute\*', ces opcodes peuvent alors tourner a\*` plein re\*'gime et chercher tre\*`s rapidement. .Sh "Extraire ce qui est reconnu" .IX Subsection "Extraire ce qui est reconnu" Les meta\-caracte\*`res de regroupement \f(CW\*(C`()\*(C'\fR servent aussi a\*` une fonction totalement diffe\*'rente\ : ils permettent l'extraction des parties d'une chai\*^ne qui ont trouve\*' une correspondance. C'est tre\*`s pratique pour trouver ce qui a e\*'te\*' reconnu et pour le traitement de texte en ge\*'ne\*'ral. Pour chaque groupe, la partie qui a e\*'te\*' reconnue est stocke\*'e dans les variables spe\*'ciales \f(CW$1\fR, \&\f(CW$2\fR, etc. Elles peuvent e\*^tre utilise\*'es comme des variables ordinaires\ : .PP .Vb 6 \& # extraction des heures, minutes et secondes \& if ($time =~ /(\ed\ed):(\ed\ed):(\ed\ed)/) { # reconnai\*^t le format hh:mm:ss \& $heures = $1; \& $minutes = $2; \& $secondes = $3; \& } .Ve .PP Pour l'instant, nous savons que, dans un contexte scalaire, \f(CW\*(C`$time\ =~\ /(\ed\ed):(\ed\ed):(\ed\ed)/\*(C'\fR\ retourne une valeur vraie ou fausse. Dans un contexte de liste, en revanche, il retourne la liste de valeurs reconnues \&\f(CW\*(C`($1,$2,$3)\*(C'\fR. Nous pouvons donc e\*'crire du code plus compact\ : .PP .Vb 2 \& # extraction des heures, minutes et secondes \& ($heures, $minutes, $secondes) = ($time =~ /(\ed\ed):(\ed\ed):(\ed\ed)/); .Ve .PP Si les regroupements sont imbrique\*'s dans l'expression rationnelle, \f(CW$1\fR recevra le groupe dont la parenthe\*`se ouvrante est la plus a\*` gauche, \f(CW$2\fR recevra le groupe dont la parenthe\*`se ouvrante est la seconde la plus a\*` gauche, etc. Par exemple, voici une expression rationnelle complexe et les variables correspondantes indique\*'es au-dessous\ : .PP .Vb 2 \& /(ab(cd|ef)((gi)|j))/; \& 1 2 34 .Ve .PP donc si cette expression rationnelle est reconnue, \f(CW$2\fR devrait contenir soit 'cd' soit 'ef'. De manie\*`re pratique, perl assigne a\*` \&\f(CW$+\fR la chai\*^ne associe\*'e au plus haut nume\*'ro des \f(CW$1\fR, \f(CW$2\fR, ... qui a e\*'te\*' le plus re\*'cemment affecte\*'e. .PP Associe\*'es avec les variables \f(CW$1\fR, \f(CW$2\fR, ..., on trouve les \fBre\*'fe\*'rences arrie\*`res\fR\ : \f(CW\*(C`\e1\*(C'\fR, \f(CW\*(C`\e2\*(C'\fR, ... Les re\*'fe\*'rences arrie\*`res sont simplement des variables de reconnaissance qui peuvent e\*^tre utilise\*'es \fIa\*` l'inte\*'rieur\fR de l'expression rationnelle. C'est une fonctionnalite\*' vraiment sympathique \- ce qui est reconnu plus tard dans une expression rationnelle peut de\*'pendre de ce qui a e\*'te\*' reconnu plus to\*^t dans l'expression rationnelle. Supposons que nous voulons chercher les mots double\*'s dans un texte comme 'the the'. L'expression rationnelle suivante trouve tous les mots de trois lettres double\*'s avec un espace entre les deux\ : .PP .Vb 1 \& /(\ew\ew\ew)\es\e1/; .Ve .PP Le regroupement affecte une valeur a\*` \e1 et donc la me\*^me se\*'quence de 3 lettres est utilise\*'e pour les deux parties. Voici quelques mots avec des parties re\*'pe\*'te\*'es\ : .PP .Vb 7 \& % simple_grep '^(\ew\ew\ew\ew|\ew\ew\ew|\ew\ew|\ew)\e1$' /usr/dict/words \& beriberi \& booboo \& coco \& mama \& murmur \& papa .Ve .PP L'expression rationnelle commence par un regroupement qui conside\*`re d'abord les combinaisons de 4 lettres, puis de 3 lettres, etc. et utilise ensuite \&\f(CW\*(C`\e1\*(C'\fR pour chercher une re\*'pe\*'tition. Bien que \f(CW$1\fR et \f(CW\*(C`\e1\*(C'\fR repre\*'sente la me\*^me chose, faites attention a\*` n'utiliser les variables \f(CW$1\fR, \f(CW$2\fR, ... qu'a\*` l'exte\*'rieur d'une expression rationnelle et a\*` n'utiliser les re\*'fe\*'rences arrie\*`res \f(CW\*(C`\e1\*(C'\fR, \f(CW\*(C`\e2\*(C'\fR, ... qu'a\*` l'inte\*'rieur d'une expression rationnelle; ne pas y pre\*^ter attention peut amener a\*` des re\*'sultats surprenants et/ou inde\*'finis. .PP En plus de ce qui a e\*'te\*' reconnu, Perl 5.6.0 fournit aussi la position de ce qui a e\*'te\*' reconnu gra\*^ce aux tableaux \f(CW\*(C`@\-\*(C'\fR et \f(CW\*(C`@+\*(C'\fR. \f(CW\*(C`$\-[0]\*(C'\fR est la position du de\*'but de l'ensemble de la reconnaissance et \f(CW$+[0]\fR est la position de la fin. De manie\*`re similaire, \f(CW\*(C`$\-[n]\*(C'\fR est la position du de\*'but du groupe \f(CW$n\fR et \f(CW$+[n]\fR est la position de sa fin. Si \f(CW$n\fR est inde\*'fini alors \f(CW\*(C`$\-[n]\*(C'\fR et \&\f(CW$+[n]\fR le sont aussi. Donc le code\ : .PP .Vb 5 \& $x = "Mmm...donut, thought Homer"; \& $x =~ /^(Mmm|Yech)\e.\e.\e.(donut|peas)/; # reconnu \& foreach $expr (1..$#\-) { \& print "Match $expr: '${$expr}' at position ($\-[$expr],$+[$expr])\en"; \& } .Ve .PP affiche\ : .PP .Vb 2 \& Match 1: 'Mmm' at position (0,3) \& Match 2: 'donut' at position (6,11) .Ve .PP Me\*^me s'il n'y a aucun regroupement dans l'expression rationnelle, il est encore possible de retrouver exactement ce qui a e\*'te\*' reconnu dans la chai\*^ne. Si vous les utilisez, perl donnera pour valeur a\*` \f(CW$`\fR la partie de la chai\*^ne qui est avant ce qui a e\*'te\*' reconnu, a\*` \f(CW$&\fR la partie de la chai\*^ne qui a e\*'te\*' reconnue et a\*` \f(CW$'\fR la partie de la chai\*^ne qui est apre\*`s ce qui a e\*'te\*' reconnu. Un exemple\ : .PP .Vb 3 \& $x = "the cat caught the mouse"; \& $x =~ /cat/; # $` = 'the ', $& = 'cat', $' = ' caught the mouse' \& $x =~ /the/; # $` = '', $& = 'the', $' = ' cat caught the mouse' .Ve .PP Lors de la seconde mise en correspondance, \f(CW\*(C`$`\ =\ ''\*(C'\fR\ parce que l'expression rationnelle est reconnue au premier caracte\*`re dans la chai\*^ne et elle ne voit donc jamais le second 'the'. Il est important de noter que l'utilisation de \f(CW$`\fR et \f(CW$'\fR ralentissent un peu le processus de reconnaissance des expressions rationnelles et que l'utilisation de \f(CW$&\fR le ralentit aussi, mais un peu moins parce que si ces variables sont utilise\*'es une fois pour une expression rationnelle, elles sont alors calcule\*'es pour \&\fBtoutes\fR les expressions rationnelles du programme. Donc si les performances font parties des buts dans votre projet, elles doivent e\*^tre e\*'vite\*'es. Pre\*'fe\*'rez alors l'utilisation de \f(CW\*(C`@\-\*(C'\fR et de \f(CW\*(C`@+\*(C'\fR\ : .PP .Vb 3 \& $` est la me\*^me chose que substr( $x, 0, $\-[0] ) \& $& est la me\*^me chose que substr( $x, $\-[0], $+[0]\-$\-[0] ) \& $' est la me\*^me chose que substr( $x, $+[0] ) .Ve .Sh "Reconnaissances re\*'pe\*'te\*'es" .IX Subsection "Reconnaissances re'pe'te'es" Les exemples de la section pre\*'ce\*'dente pre\*'sentent un de\*'faut. Nous ne reconnaissons que les mots de 3 lettres ou des syllabes de 4 lettres ou moins. Nous aimerions pouvoir reconnai\*^tre des mots ou des syllabes de n'importe quelle longueur sans e\*'crire de choses horribles comme \&\f(CW\*(C`\ew\ew\ew\ew|\ew\ew\ew|\ew\ew|\ew\*(C'\fR. .PP C'est exactement pour re\*'pondre a\*` ce besoin que les meta\-caracte\*`res \&\fBquantificateurs\fR \f(CW\*(C`?\*(C'\fR, \f(CW\*(C`*\*(C'\fR, \f(CW\*(C`+\*(C'\fR et \f(CW\*(C`{}\*(C'\fR ont e\*'te\*' cre\*'e\*'s. Ils nous permettent de spe\*'cifier le nombre de re\*'pe\*'titions d'une portion d'une expression rationnelle que nous conside\*'rons comme acceptable. Les quantificateurs se placent juste apre\*`s le caracte\*`re, la classe de caracte\*`res ou le regroupement dont ils pre\*'cisent le nombre de re\*'pe\*'titions. Ils ont la signification suivante\ : .IP "\(bu" 4 \&\f(CW\*(C`a?\*(C'\fR = reconnai\*^t 'a' 1 ou 0 fois .IP "\(bu" 4 \&\f(CW\*(C`a*\*(C'\fR = reconnai\*^t 'a' 0 ou plusieurs fois .IP "\(bu" 4 \&\f(CW\*(C`a+\*(C'\fR = reconnai\*^t 'a' 1 ou plusieurs fois .IP "\(bu" 4 \&\f(CW\*(C`a{n,m}\*(C'\fR = reconnai\*^t au moins \f(CW\*(C`n\*(C'\fR 'a', mais pas plus que \f(CW\*(C`m\*(C'\fR 'a'. .IP "\(bu" 4 \&\f(CW\*(C`a{n,}\*(C'\fR = reconnai\*^t au moins \f(CW\*(C`n\*(C'\fR 'a' ou plus .IP "\(bu" 4 \&\f(CW\*(C`a{n}\*(C'\fR = reconnai\*^t exactement \f(CW\*(C`n\*(C'\fR 'a' .PP Voici quelques exemples\ : .PP .Vb 12 \& /[a\-z]+\es+\ed*/; # reconnai\*^t un mot en minuscules, au moins un espace et \& # n'importe quel nombre de chiffres \& /(\ew+)\es+\e1/; # reconnai\*^t la re\*'pe\*'tition d'un mot de n'importe \& # quelle longueur \& /y(es)?/i; # reconnai\*^t 'y', 'Y', ou un 'yes' insensible a\*` la cass \& $year =~ /\ed{2,4}/; # s'assure que l'anne\*'e est au moins sur 2 chiffres \& # et pas sur plus de 4 chiffres \& $year =~ /\ed{4}|\ed{2}/; # meilleur reconnaissance ; supprime le cas \& # d'une anne\*'e sur 3 chiffres \& $year =~ /\ed{2}(\ed{2})?/; # la me\*^me chose e\*'crite diffe\*'rement ; de plus, \& # produit $1 ce que ne faisaient pas les \& # exemples pre\*'ce\*'dents \& \& % simple_grep '^(\ew+)\e1$' /usr/dict/words # c'est simple... non ? \& beriberi \& booboo \& coco \& mama \& murmur \& papa .Ve .PP Quel que soit le quantificateur, perl essaye de reconnai\*^tre la chai\*^ne la plus longue possible tant qu'elle peut e\*^tre mise en correspondance avec l'expression rationnelle. Donc dans \f(CW\*(C`/a?.../\*(C'\fR, perl essayera d'abord de reconnai\*^tre l'expression rationnelle avec un \f(CW\*(C`a\*(C'\fR pre\*'sent ; en cas d'e\*'chec, perl re\*'essayera sans le \f(CW\*(C`a\*(C'\fR. Avec le quantificateur \f(CW\*(C`*\*(C'\fR, nous obtenons\ : .PP .Vb 5 \& $x = "the cat in the hat"; \& $x =~ /^(.*)(cat)(.*)$/; # est reconnue avec \& # $1 = 'the ' \& # $2 = 'cat' \& # $3 = ' in the hat' .Ve .PP C'est exactement ce que nous attendions, la mise en correspondance trouve le seul \f(CW\*(C`cat\*(C'\fR pre\*'sent dans la chai\*^ne et se cale dessus. Conside\*'rons maintenant cette expression rationnelle\ : .PP .Vb 4 \& $x =~ /^(.*)(at)(.*)$/; # est reconnue avec \& # $1 = 'the cat in the h' \& # $2 = 'at' \& # $3 = '' (reconnaissance de la chai\*^ne vide) .Ve .PP On aurait pu croire que perl trouverait le \f(CW\*(C`at\*(C'\fR dans \f(CW\*(C`cat\*(C'\fR et se serait arre\*^te\*' la\*` mais cela n'aurait pas donne\*' la chai\*^ne la plus longue possible pour le premier quantificateur \f(CW\*(C`.*\*(C'\fR. En fait, le premier quantificateur \f(CW\*(C`.*\*(C'\fR consomme la plus grande partie possible de la chai\*^ne tout en laissant a\*` l'expression rationnelle la possibilite\*' d'e\*^tre reconnue. Dans cet exemple, cela signifie que la se\*'quence \f(CW\*(C`at\*(C'\fR est mise en correspondance avec le dernier \&\f(CW\*(C`cat\*(C'\fR de la chai\*^ne. L'autre principe important illustre\*' ici est que lorsque qu'il y a plusieurs e\*'le\*'ments dans une expression rationnelle, c'est le quantificateur le plus a\*` gauche, s'il existe, qui est servi en premier et qui laisse le minimum au reste de l'expression rationnelle. Donc dans notre exemple, c'est le premier quantificateur \f(CW\*(C`.*\*(C'\fR qui consomme la plus grande partie de la chai\*^ne alors que le second quantificateur \f(CW\*(C`.*\*(C'\fR obtient la chai\*^ne vide. Les quantificateurs qui consomment autant que possible sont qualifie\*'s de \&\fBmaximaux\fR ou de \fBgourmands\fR. .PP Lorsque une expression rationnelle peut e\*^tre mise en correspondance avec une chai\*^ne de diffe\*'rentes fac\*,ons, nous pouvons utiliser les principes suivants pour pre\*'dire la manie\*`re dont elle sera reconnue\ : .IP "\(bu" 4 Principe 0: Tout d'abord, une expression rationnelle sera toujours reconnue a\*` la position la plus a\*` gauche possible dans la chai\*^ne. .IP "\(bu" 4 Principe 1: Dans un choix \f(CW\*(C`a|b|c...\*(C'\fR, c'est la branche la plus a\*` gauche permettant une reconnaissance de l'ensemble de l'expression rationnelle qui sera choisie en premier. .IP "\(bu" 4 Principe 2: Les quantificateurs gourmands comme \f(CW\*(C`?\*(C'\fR, \f(CW\*(C`*\*(C'\fR, \f(CW\*(C`+\*(C'\fR et \f(CW\*(C`{n,m}\*(C'\fR consomme la plus grande partie possible de la chai\*^ne tant qu'ils permettent encore de reconnai\*^tre l'ensemble de l'expression rationnelle. .IP "\(bu" 4 Principe 3: s'il existe plusieurs e\*'le\*'ments dans une expression rationnelle, le quantificateur gourmand le plus a\*` gauche, s'il existe, sera mis en correspondance avec la partie de la chai\*^ne la plus longue possible tout en gardant possible la reconnaissance de toute l'expression rationnelle. Le quantificateur gourmand suivant, s'il existe, sera mis en correspondance avec la partie la plus longue possible de ce qui reste de la chai\*^ne tout en gardant possible la reconnaissance de toute l'expression rationnelle. Et ainsi de suite, jusqu'a\*` la reconnaissance comple\*`te de l'expression rationnelle. .PP Comme vu pre\*'ce\*'demment, le Principe 0 est prioritaire sur tous les autres \- l'expression rationnelle est reconnue le plus to\*^t possible en utilisant les autres principes pour de\*'terminer comment l'expression rationnelle est reconnue a\*` cette position la plus a\*` gauche. .PP Voici des exemples qui montrent l'application de ces principes\ : .PP .Vb 5 \& $x = "The programming republic of Perl"; \& $x =~ /^(.+)(e|r)(.*)$/; # est reconnue avec \& # $1 = 'The programming republic of Pe' \& # $2 = 'r' \& # $3 = 'l' .Ve .PP L'expression rationnelle est reconnue a\*` la position la plus to\*^t, \f(CW'T'\fR. On pourrait penser que le \f(CW\*(C`e\*(C'\fR le plus a\*` gauche de l'alternative devrait e\*^tre reconnu mais le \f(CW\*(C`r\*(C'\fR produit une chai\*^ne plus longue pour le premier quantificateur. .PP .Vb 3 \& $x =~ /(m{1,2})(.*)$/; # est reconnue avec \& # $1 = 'mm' \& # $2 = 'ing republic of Perl' .Ve .PP Ici, la mise en correspondance au plus to\*^t se fait au premier \f(CW'm'\fR de \&\f(CW\*(C`programming\*(C'\fR. \f(CW\*(C`m{1,2}\*(C'\fR est le premier quantificateur et donc il cherche la correspondance maximale \f(CW\*(C`mm\*(C'\fR. .PP .Vb 3 \& $x =~ /.*(m{1,2})(.*)$/; # est reconnue avec \& # $1 = 'm' \& # $2 = 'ing republic of Perl' .Ve .PP Ici, l'expression rationnelle est mise en correspondance de\*`s le de\*'but de la chai\*^ne. Le premier quantificateur \f(CW\*(C`.*\*(C'\fR consomme le plus de caracte\*`res possibles en ne laissant qu'un seul \f(CW'm'\fR pour le second quantificateur \&\f(CW\*(C`m{1,2}\*(C'\fR. .PP .Vb 4 \& $x =~ /(.?)(m{1,2})(.*)$/; # est reconnue avec \& # $1 = 'a' \& # $2 = 'mm' \& # $3 = 'ing republic of Perl' .Ve .PP Ici, \f(CW\*(C`.?\*(C'\fR consomme le maximum de caracte\*`res (un caracte\*`re) a\*` la position la plus a\*` gauche possible dans la chai\*^ne, le \f(CW'a'\fR dans \f(CW\*(C`programming\*(C'\fR, en laissant l'opportunite\*' a\*` \f(CW\*(C`m{1,2}\*(C'\fR de correspondre aux deux \f(CW\*(C`m\*(C'\fR. Finalement\ : .PP .Vb 1 \& "aXXXb" =~ /(X*)/; # est reconnue avec $1 = '' .Ve .PP parce qu'il peut reconnai\*^tre ze\*'ro \f(CW'X'\fR au tout de\*'but de la chai\*^ne. Si vous voulez re\*'ellement reconnai\*^tre au moins un \f(CW'X'\fR, utilisez \f(CW\*(C`X+\*(C'\fR au lieu de \&\f(CW\*(C`X*\*(C'\fR. .PP Parfois la gourmandise n'est pas une bonne chose. Dans ce cas, nous aimerions des quantificateurs qui reconnaissent une partie \fIminimale\fR de la chai\*^ne pluto\*^t que \fImaximale\fR. Pour cela, Larry Wall a cre\*'e\*' les quantificateurs \&\fBminimaux\fR ou quantificateurs \fBsobres\fR\ : \f(CW\*(C`??\*(C'\fR,\f(CW\*(C`*?\*(C'\fR, \f(CW\*(C`+?\*(C'\fR et \f(CW\*(C`{}?\*(C'\fR. Ce sont les quantificateurs habituels auxquels on ajoute un \f(CW\*(C`?\*(C'\fR. Ils ont la se\*'mantique suivante\ : .IP "\(bu" 4 \&\f(CW\*(C`a??\*(C'\fR = reconnai\*^t un 'a' 0 ou 1 fois. Essaie 0 d'abord puis 1 ensuite. .IP "\(bu" 4 \&\f(CW\*(C`a*?\*(C'\fR = reconnai\*^t ze\*'ro 'a' ou plus mais un minimum de fois. .IP "\(bu" 4 \&\f(CW\*(C`a+?\*(C'\fR = reconnai\*^t un 'a' ou plus mais un minimum de fois. .IP "\(bu" 4 \&\f(CW\*(C`a{n,m}?\*(C'\fR = reconnai\*^t entre \f(CW\*(C`n\*(C'\fR et \f(CW\*(C`m\*(C'\fR 'a' mais un minimum de fois. .IP "\(bu" 4 \&\f(CW\*(C`a{n,}?\*(C'\fR = reconnai\*^t au moins \f(CW\*(C`n\*(C'\fR 'a' mais un minimum de fois. .IP "\(bu" 4 \&\f(CW\*(C`a{n}?\*(C'\fR = reconnai\*^t exactement \f(CW\*(C`n\*(C'\fR 'a'. C'est e\*'quivalent a\*` \f(CW\*(C`a{n}\*(C'\fR. Ce n'est donc que pour rendre la notation cohe\*'rente. .PP Reprenons les exemples pre\*'ce\*'dents mais avec des quantificateurs minimaux\ : .PP .Vb 5 \& $x = "The programming republic of Perl"; \& $x =~ /^(.+?)(e|r)(.*)$/; # est reconnue avec \& # $1 = 'Th' \& # $2 = 'e' \& # $3 = ' programming republic of Perl' .Ve .PP La chai\*^ne minimale permettant a\*` la fois de reconnai\*^tre le de\*'but de chai\*^ne \&\f(CW\*(C`^\*(C'\fR et l'alternative est \f(CW\*(C`Th\*(C'\fR avec l'alternative \f(CW\*(C`e|r\*(C'\fR qui reconnai\*^t \&\f(CW\*(C`e\*(C'\fR. Le second quantificateur est libre de consommer tout le reste de la chai\*^ne. .PP .Vb 3 \& $x =~ /(m{1,2}?)(.*?)$/; # est reconnue avec \& # $1 = 'm' \& # $2 = 'ming republic of Perl' .Ve .PP La premie\*`re position a\*` partir de laquelle cette expression rationnelle peut e\*^tre reconnue et le premier \f(CW'm'\fR de \f(CW\*(C`programming\*(C'\fR. A\*` cette position, le sobre \f(CW\*(C`m{1,2}?\*(C'\fR reconnai\*^t juste un \f(CW'm'\fR. Ensuite, bien que le second quantificateur \f(CW\*(C`.*?\*(C'\fR pre\*'fe\*`re reconnai\*^tre un minimum de caracte\*`res, il est contraint par l'ancre de fin de chai\*^ne \f(CW\*(C`$\*(C'\fR a\*` reconnai\*^tre tout le reste de la chai\*^ne. .PP .Vb 4 \& $x =~ /(.*?)(m{1,2}?)(.*)$/; # est reconnue avec \& # $1 = 'The progra' \& # $2 = 'm' \& # $3 = 'ming republic of Perl' .Ve .PP Dans cette expression rationnelle, vous espe\*'riez peut\-e\*^tre que le premier quantificateur minimal \f(CW\*(C`.*?\*(C'\fR soit mis en correspondance avec la chai\*^ne vide puisqu'il n'est pas contraint a\*` s'ancrer en de\*'but de chai\*^ne par \f(CW\*(C`^\*(C'\fR. Mais ici le principe 0 s'applique. Puisqu'il est possible de reconnai\*^tre l'ensemble de l'expression rationnelle en s'ancrant au de\*'but de la chai\*^ne, ce sera cet ancrage qui sera choisi. Donc le premier quantificateur doit reconnai\*^tre tout jusqu'au premier \f(CW\*(C`m\*(C'\fR et le troisie\*`me quantificateur reconnai\*^t le reste de la chai\*^ne. .PP .Vb 4 \& $x =~ /(.??)(m{1,2})(.*)$/; # est reconnue avec \& # $1 = 'a' \& # $2 = 'mm' \& # $3 = 'ing republic of Perl' .Ve .PP Comme dans l'expression rationnelle pre\*'ce\*'dente, le premier quantificateur peut correspondre au plus to\*^t sur le \f(CW'a'\fR, c'est donc ce qui est retenu. Le second quantificateur est gourmand donc il reconnai\*^t \f(CW\*(C`mm\*(C'\fR et le troisie\*`me reconnai\*^t le reste de la chai\*^ne. .PP Nous pouvons modifier le principe 3 pre\*'ce\*'dent pour prendre en compte les quantificateurs sobres\ : .IP "\(bu" 4 Principe 3: s'il existe plusieurs e\*'le\*'ments dans une expression rationnelle, le quantificateur gourmand (ou sobre) le plus a\*` gauche, s'il existe, sera mis en correspondance avec la partie de la chai\*^ne la plus longue (ou la plus courte) possible tout en gardant possible la reconnaissance de toute l'expression rationnelle. Le quantificateur gourmand (ou sobre) suivant, s'il existe, sera mis en correspondance avec la partie la plus longue (ou la plus courte) possible de ce qui reste de la chai\*^ne tout en gardant possible la reconnaissance de toute l'expression rationnelle. Et ainsi de suite, jusqu'a\*` la reconnaissance comple\*`te de l'expression rationnelle. .PP Comme avec les alternatives, les quantificateurs sont susceptibles de de\*'clencher des retours arrie\*`re. Voici l'analyse pas a\*` pas d'un exemple\ : .PP .Vb 5 \& $x = "the cat in the hat"; \& $x =~ /^(.*)(at)(.*)$/; # est reconnue avec \& # $1 = 'the cat in the h' \& # $2 = 'at' \& # $3 = '' (reconnaissance de la chai\*^ne vide) .Ve .IP "1." 4 On de\*'marre avec la premie\*`re lettre de la chai\*^ne 't'. .IP "2." 4 Le premier quantificateur '.*' commence par reconnai\*^tre l'ensemble de la chai\*^ne 'the cat in the hat'. .IP "3." 4 Le 'a' de l'e\*'le\*'ment 'at' ne peut pas e\*^tre mis en correspondance avec la fin de la chai\*^ne. Retour arrie\*`re d'un caracte\*`re. .IP "4." 4 Le 'a' de l'e\*'le\*'ment 'at' ne peut pas e\*^tre mis en correspondance avec la dernie\*`re lettre de la chai\*^ne 't'. Donc a\*` nouveau un retour arrie\*`re d'un caracte\*`re. .IP "5." 4 Maintenant nous pouvons reconnai\*^tre le 'a' et le 't'. .IP "6." 4 On continue avec le troisie\*`me e\*'le\*'ment '.*'. Puisque nous sommes a\*` la fin de la chai\*^ne, '.*' ne peut donc reconnai\*^tre que 0 caracte\*`re. On lui affecte donc la chai\*^ne vide. .IP "7." 4 C'est fini. .PP La plupart du temps, tous ces aller-retours ont lieu tre\*`s rapidement et la recherche est rapide. Par contre, il existe quelques expressions rationnelles pathologiques dont le temps d'exe\*'cution augmente exponentiellement avec la taille de la chai\*^ne. Une structure typique est de la forme\ : .PP .Vb 1 \& /(a|b+)*/; .Ve .PP Le proble\*`me est l'imbrication de deux quantificateurs inde\*'termine\*'s. Il y a de nombreuses manie\*`res de partitionner une chai\*^ne de longueur n entre le \f(CW\*(C`+\*(C'\fR et le \&\f(CW\*(C`*\*(C'\fR\ : une re\*'pe\*'tition avec \f(CW\*(C`b+\*(C'\fR de longueur n, deux re\*'pe\*'titions avec le premier \f(CW\*(C`b+\*(C'\fR de longueur k et le second de longueur n\-k, m re\*'pe\*'titions dont la somme des longueurs est e\*'gale a n, etc. En fait, le nombre de manie\*`res diffe\*'rentes de partitionner une chai\*^ne est exponentielle en fonction de sa longueur. Une expression rationnelle peut e\*^tre chanceuse et e\*^tre reconnue tre\*`s to\*^t mais s'il n'y a pas de reconnaissance possible, perl essayera \fItoutes\fR les possibilite\*'s avant de conclure a\*` l'e\*'chec. Donc, soyez prudents lorsque vous imbriquez des \f(CW\*(C`*\*(C'\fR, des \f(CW\*(C`{n,m}\*(C'\fR et/ou des \f(CW\*(C`+\*(C'\fR. Le livre \fIMastering regular expressions\fR par Jeffrey Friedl donne de tre\*`s bonnes explications sur ce proble\*`me en particulier et sur tous les autres proble\*`mes de performances. .Sh "Construction d'une expression rationnelle" .IX Subsection "Construction d'une expression rationnelle" A\*` ce point, nous avons couvert tous les concepts de base des expressions rationnelles. Nous pouvons donc pre\*'senter un exemple plus complet d'utilisation des expressions rationnelles. Nous allons construire une expression rationnelle qui reconnai\*^t les nombres. .PP La premie\*`re ta\*^che de la construction d'une expression rationnelle consiste a\*` de\*'cider ce que nous voulons reconnai\*^tre et ce que nous voulons exclure. Dans notre cas, nous voulons reconnai\*^tre a\*` la fois les entiers et les nombres en virgule flottante et nous voulons rejeter les chai\*^nes qui ne sont pas des nombres. .PP La ta\*^che suivante permet de de\*'couper le proble\*`me en plusieurs petits proble\*`mes qui seront plus simplement transforme\*'s en expressions rationnelles. .PP Le cas le plus simple concerne les entiers. Ce sont une suite de chiffres pre\*'ce\*'de\*'e d'un e\*'ventuel signe. Les chiffres peuvent e\*^tre repre\*'sente\*'s par \f(CW\*(C`\ed+\*(C'\fR et le signe peut e\*^tre reconnu par \f(CW\*(C`[+\-]\*(C'\fR. Donc l'expression rationnelle pour les entiers est\ : .PP .Vb 1 \& /[+\-]?\ed+/; # reconnai\*^t les entiers .Ve .PP Un nombre en virgule flottante contient potentiellement un signe, une partie entie\*`re, un se\*'parateur de\*'cimal (un point), une partie de\*'cimale et un exposant. Plusieurs de ces parties sont optionnelles donc nous devons ve\*'rifier les diffe\*'rentes possibilite\*'s. Les nombres en virgule flottante bien forme\*'s contiennent entre autres 123., 0.345, .34, \-1e6 et 25.4E\-72. Comme pour les entiers, le signe au de\*'part est comple\*`tement optionnel et peut e\*^tre reconnu par \f(CW\*(C`[+\-]?\*(C'\fR. Nous pouvons voir que s'il n'a pas d'exposant, un nombre en virgule flottante doit contenir un se\*'parateur de\*'cimal ou alors c'est un entier. Nous pourrions e\*^tre tente\*'s d'utiliser \f(CW\*(C`\ed*\e.\ed*\*(C'\fR mais cela pourrait aussi reconnai\*^tre un se\*'parateur de\*'cimal seul (qui n'est pas un nombre). Donc, les trois cas de nombres sans exposant sont\ : .PP .Vb 3 \& /[+\-]?\ed+\e./; # 1., 321., etc. \& /[+\-]?\e.\ed+/; # .1, .234, etc. \& /[+\-]?\ed+\e.\ed+/; # 1.0, 30.56, etc. .Ve .PP On peut combiner cela en une seule expression rationnelle\ : .PP .Vb 1 \& /[+\-]?(\ed+\e.\ed+|\ed+\e.|\e.\ed+)/; # virgule flottante, sans exposant .Ve .PP Dans ce choix, il est important de placer \f(CW'\ed+\e.\ed+'\fR avant \f(CW'\ed+\e.'\fR. Si \&\f(CW'\ed+\e.'\fR e\*'tait en premier, l'expression rationnelle pourrait e\*^tre reconnue en ignorant la partie de\*'cimale du nombre. .PP Conside\*'rons maintenant les nombres en virgule flottante avec exposant. Le point cle\*' ici est que les nombres avec se\*'parateur de\*'cimal \fIainsi\fR que les entiers sont autorise\*'s devant un exposant. Ensuite la reconnaissance de l'exposant, comme celle du signe, est inde\*'pendante du fait que le nombre posse\*`de ou nom une partie de\*'cimale. Elle peut donc e\*^tre de\*'couple\*'e de la mantisse. La forme de l'expression rationnelle comple\*`te devient donc claire maintenant\ : .PP .Vb 1 \& /^(signe optionnel)(entier | mantisse)(exposant optionnel)$/; .Ve .PP L'expression est un \f(CW\*(C`e\*(C'\fR ou un \f(CW\*(C`E\*(C'\fR suivi d'un entier. Donc l'expression rationnelle de l'exposant est\ : .PP .Vb 1 \& /[eE][+\-]?\ed+/; # exposant .Ve .PP En assemblant toutes les parties ensemble nous obtenons l'expression rationnelle qui reconnai\*^t les nombres\ : .PP .Vb 1 \& /^[+\-]?(\ed+\e.\ed+|\ed+\e.|\e.\ed+|\ed+)([eE][+\-]?\ed+)?$/; # Ta da! .Ve .PP De longues expressions rationnelles comme celle-ci peuvent peut\-e\*^tre impressionner vos amis mais elles sont difficiles a\*` de\*'chiffrer. Dans des situations complexes comme celle\-ci, le modificateur \f(CW\*(C`//x\*(C'\fR est tre\*`s pratique. Il vous permet de placer des espaces et des commentaires n'importe ou\*` dans votre expression sans en changer la signification. En l'utilisant, nous pouvons re\*'e\*'crire notre expression sous une forme plus plaisante\ : .PP .Vb 11 \& /^ \& [+\-]? # en premier, reconnaissance du signe optionnel \& ( # ensuite reconnaissance d'un entier ou d'un \& # nombre en virgule flottante \& \ed+\e.\ed+ # mantisse de la forme a.b \& |\ed+\e. # mantisse de la forme a. \& |\e.\ed+ # mantisse de la forme .b \& |\ed+ # entier de la forme a \& ) \& ([eE][+\-]?\ed+)? # finalement, reconnaissance optionnelle d'un exposant \& $/x; .Ve .PP Si les espaces ne sont pas pris en compte, comment inclure un caracte\*`re espace dans une telle expression rationnelle ? Il suffit de le XbackslasherX \f(CW'\e\ '\fR\ ou de le placer dans une classe de caracte\*`res \f(CW\*(C`[\ ]\*(C'\fR\ . La me\*^me chose est valable pour le die\*`se\ : utilisez \f(CW\*(C`\e#\*(C'\fR ou \f(CW\*(C`[#]\*(C'\fR. Par exemple, Perl autorise un espace entre le signe la mantisse ou l'entier. Nous pouvons ajouter cela dans notre expression rationnelle comme suit\ : .PP .Vb 11 \& /^ \& [+\-]?\e * # en premier, reconnaissance du signe optionnel *et des espaces* \& ( # ensuite reconnaissance d'un entier ou d'un \& # nombre en virgule flottante \& \ed+\e.\ed+ # mantisse de la forme a.b \& |\ed+\e. # mantisse de la forme a. \& |\e.\ed+ # mantisse de la forme .b \& |\ed+ # entier de la forme a \& ) \& ([eE][+\-]?\ed+)? # finalement, reconnaissance optionnelle d'un exposant \& $/x; .Ve .PP Sous cette forme, il est plus simple de de\*'couvrir un moyen de simplifier le choix. Les branches 1, 2 et 4 du choix commencent toutes par \f(CW\*(C`\ed+\*(C'\fR qu'on doit donc pouvoir factoriser\ : .PP .Vb 12 \& /^ \& [+\-]?\e * # en premier, reconnaissance du signe optionnel \& ( # ensuite reconnaissance d'un entier ou d'un \& # nombre en virgule flottante \& \ed+ # on commence par a ... \& ( \& \e.\ed* # mantisse de la forme a. ou a.b \& )? # ? pour les entiers de la forme a \& |\e.\ed+ # mantisse de la forme .b \& ) \& ([eE][+\-]?\ed+)? # finalement, reconnaissance optionnelle d'un exposant \& $/x; .Ve .PP ou e\*'crit dans sa forme compacte\ : .PP .Vb 1 \& /^[+\-]?\e *(\ed+(\e.\ed*)?|\e.\ed+)([eE][+\-]?\ed+)?$/; .Ve .PP C'est notre expression rationnelle finale. Pour re\*'capituler, nous avons construit notre expression rationnelle\ : .IP "\(bu" 4 en spe\*'cifiant la ta\*^che en de\*'tail, .IP "\(bu" 4 en de\*'coupant le proble\*`me en plus petites parties, .IP "\(bu" 4 en transformant les petites parties en expressions rationnelles, .IP "\(bu" 4 en combinant les expressions rationnelles, .IP "\(bu" 4 et en optimisant l'expression rationnelle combine\*'e finale. .PP On peut faire le paralle\*`le avec les diffe\*'rentes e\*'tapes de l'e\*'criture d'un programme. C'est normal puisque les expressions rationnelles sont des programmes e\*'crits dans un petit langage informatique de spe\*'cification de motifs. .Sh "Utilisation des expressions rationnelles en Perl" .IX Subsection "Utilisation des expressions rationnelles en Perl" Pour terminer cette premie\*`re partie, nous allons examiner brie\*`vement comment les expressions rationnelles sont utilise\*'es dans un programme Perl. Comment s'inte\*`grent\-elles a\*` la syntaxe Perl ? .PP Nous avons de\*'ja\*` parle\*' de l'ope\*'rateur de recherche de correspondances dans sa forme par de\*'faut \f(CW\*(C`/regexp/\*(C'\fR ou avec des de\*'limiteurs arbitraires \&\f(CW\*(C`m!regexp!\*(C'\fR. Nous avons utilise\*' l'ope\*'rateur de mise en correspondance \f(CW\*(C`=~\*(C'\fR ainsi que sa ne\*'gation \f(CW\*(C`!~\*(C'\fR pour rechercher les correspondances. Associe\*' avec l'ope\*'rateur de recherche de correspondances, nous avons pre\*'sente\*' les modificateurs permettant de traiter de simples lignes \f(CW\*(C`//s\*(C'\fR, des multi-lignes \&\f(CW\*(C`//m\*(C'\fR, des expressions insensibles a\*` la casse \f(CW\*(C`//i\*(C'\fR et des expressions e\*'tendues \f(CW\*(C`//x\*(C'\fR. .PP Il y a encore quelques points que vous devez connai\*^tre a\*` propos des ope\*'rateurs de mise en correspondance. Nous avons montre\*' que les variables e\*'taient substitue\*'es avant l'e\*'valuation de l'expression rationnelle\ : .PP .Vb 4 \& $pattern = 'Seuss'; \& while (<>) { \& print if /$pattern/; \& } .Ve .PP Cela affichera toutes les lignes contenant le mot \f(CW\*(C`Seuss\*(C'\fR. Par contre, ce n'est pas aussi efficace qu'il y parai\*^t car perl doit re\*'e\*'valuer \f(CW$pattern\fR a\*` chaque passage dans la boucle. Si \f(CW$pattern\fR ne doit pas changer durant la vie du script, nous pouvons ajouter le modificateur \f(CW\*(C`//o\*(C'\fR qui demande a\*` perl de n'effectuer la substitution de variables qu'une seule fois\ : .PP .Vb 6 \& #!/usr/bin/perl \& # grep simple ame\*'liore\*' \& $regexp = shift; \& while (<>) { \& print if /$regexp/o; # cela va plus vite... \& } .Ve .PP Si vous changez \f(CW$pattern\fR apre\*`s la premie\*`re substitution, perl l'ignorera. Si vous voulez que perl n'effectue aucune substitution, utilisez le de\*'limiteur spe\*'cial \f(CW\*(C`m''\*(C'\fR\ : .PP .Vb 5 \& @pattern = ('Seuss'); \& while (<>) { \& print if m'@pattern'; # correspond litte\*'rallement avec '@pattern', \& # pas avec 'Seuss' \& } .Ve .PP \&\f(CW\*(C`m''\*(C'\fR agit exactement comme les apostrophes sur les expressions rationnelles ; tout autre de\*'limiteur agit comme des guillemets. Si l'expression rationnelle s'e\*'value a\*` la chai\*^ne vide, la dernie\*`re expression rationnelle \fIutilise\*'e avec succe\*`s\fR sera utilise\*'e a\*` la place. Donc\ : .PP .Vb 3 \& "dog" =~ /d/; # 'd' correspond \& "dogbert =~ //; # mise en correspondance par \& # l'expression rationnelle 'd' pre\*'ce\*'dente .Ve .PP Le deux modificateurs restant (\f(CW\*(C`//g\*(C'\fR et \f(CW\*(C`//c\*(C'\fR) concernent les recherches multiples. Le modificateur \f(CW\*(C`//g\*(C'\fR signifie recherche globale et autorise l'ope\*'rateur de mise en correspondance a\*` correspondre autant de fois que possible. Dans un contexte scalaire, des invocations successives d'une expression rationnelle modifie\*'e par \&\f(CW\*(C`//g\*(C'\fR applique\*'e a\*` une me\*^me chai\*^ne passeront d'une correspondance a\*` une autre, en se souvenant de la position atteinte dans la chai\*^ne explore\*'e. Vous pouvez consulter ou modifier cette position gra\*^ce a\*` la fonction \f(CW\*(C`pos()\*(C'\fR. .PP L'utilisation de \f(CW\*(C`//g\*(C'\fR est montre\*'e dans l'exemple suivant. Supposons une chai\*^ne constitue\*'e de mots se\*'pare\*'s par des espaces. Si nous connaissons a\*` l'avance le nombre de mots, nous pouvons extraire les mots en utilisant les regroupements\ : .PP .Vb 5 \& $x = "cat dog house"; # 3 mots \& $x =~ /^\es*(\ew+)\es+(\ew+)\es+(\ew+)\es*$/; # correspond avec \& # $1 = 'cat' \& # $2 = 'dog' \& # $3 = 'house' .Ve .PP Mais comment faire si le nombre de mots est inde\*'termine\*' ? C'est pour ce genre de ta\*^che qu'on a cre\*'e\*' \f(CW\*(C`//g\*(C'\fR. Pour extraire tous les mots, on utilise l'expression rationnelle simple \f(CW\*(C`(\ew+)\*(C'\fR et on boucle sur toutes les correspondances possibles gra\*^ce a\*` \f(CW\*(C`/(\ew+)/g\*(C'\fR\ : .PP .Vb 3 \& while ($x =~ /(\ew+)/g) { \& print "Le mot $1 se termine a\*` la position ", pos $x, "\en"; \& } .Ve .PP qui affiche .PP .Vb 3 \& Le mot cat se termine a\*` la position 3 \& Le mot dog se termine a\*` la position 7 \& Le mot house se termine a\*` la position 13 .Ve .PP Un e\*'chec de la mise en correspondance ou un changement de chai\*^ne cible re\*'initialise la position. Si vous ne voulez pas que la position soit re\*'initialise\*'e apre\*`s un e\*'chec, ajoutez le modificateur \f(CW\*(C`//c\*(C'\fR comme dans \f(CW\*(C`/regexp/gc\*(C'\fR. La position courante dans la chai\*^ne est associe\*'e a\*` la chai\*^ne elle\-me\*^me et non a\*` l'expression rationnelle. Cela signifie que des chai\*^nes diffe\*'rentes ont des positions diffe\*'rentes et que ces positions peuvent e\*^tre modifie\*'es inde\*'pendamment. .PP Dans un contexte de liste, \f(CW\*(C`//g\*(C'\fR retourne la liste de tous les groupes mis en correspondance ou, s'il n'y a pas de groupes, la liste de toutes les reconnaissances de l'expression rationnelle entie\*`re. Donc si nous ne voulons que les mots, nous pouvons faire\ : .PP .Vb 4 \& @words = ($x =~ /(\ew+)/g); # correspond avec \& # $word[0] = 'cat' \& # $word[1] = 'dog' \& # $word[2] = 'house' .Ve .PP E\*'troitement associe\*' avec le modificateur \f(CW\*(C`//g\*(C'\fR, il existe l'ancre \&\f(CW\*(C`\eG\*(C'\fR. L'ancre \f(CW\*(C`\eG\*(C'\fR est mis en correspondance avec le point atteint lors d'une reconnaissance pre\*'ce\*'dente par \f(CW\*(C`//g\*(C'\fR. \f(CW\*(C`\eG\*(C'\fR permet de faire de la reconnaissance de\*'pendante du contexte\ : .PP .Vb 12 \& $metric = 1; # utilisation des unite\*'s me\*'triques \& ... \& $x = ; # lecture des mesures \& $x =~ /^([+\-]?\ed+)\es*/g; # obtention de la valeur \& $weight = $1; \& if ($metric) { # ve\*'rificiation d'erreur \& print "Units error!" unless $x =~ /\eGkg\e./g; \& } \& else { \& print "Units error!" unless $x =~ /\eGlbs\e./g; \& } \& $x =~ /\eG\es+(widget|sprocket)/g; # suite du traitement .Ve .PP La combinaison de \f(CW\*(C`//g\*(C'\fR et de \f(CW\*(C`\eG\*(C'\fR permet le traitement pas a\*` pas d'une chai\*^ne et l'utilisation de Perl pour de\*'terminer la suite du traitement. Actuellement, l'ancre \f(CW\*(C`\eG\*(C'\fR n'est re\*'ellement utilisable que si elle est utilise\*'e en de\*'but de motif. .PP \&\f(CW\*(C`\eG\*(C'\fR est aussi pratique lors du traitement par des expressions rationnelles d'enregistrement a\*` taille fixe. Supposons une se\*'quence d'\s-1ADN\s0, encode\*'e comme une suite de lettres \f(CW\*(C`ATCGTTGAAT...\*(C'\fR et que vous voulez trouver tous les codons du type \f(CW\*(C`TGA\*(C'\fR. Dans une se\*'quence, les codons sont des se\*'quences de 3 lettres. Nous pouvons donc conside\*'rer une chai\*^ne d'\s-1ADN\s0 comme une se\*'quence d'enregistrements de 3 lettres. L'expression rationnelle nai\*:ve\ : .PP .Vb 3 \& # C'est "ATC GTT GAA TGC AAA TGA CAT GAC" \& $dna = "ATCGTTGAATGCAAATGACATGAC"; \& $dna =~ /TGA/; .Ve .PP ne marche pas ; elle retrouvera un \f(CW\*(C`TGA\*(C'\fR mais il n'y aura aucune garantie que cette correspondance soit aligne\*'e avec une limite de codon, e.g., la sous\-chai\*^ne \f(CW\*(C`GTT\ GAA\*(C'\fR donnera une correspondance. Une meilleure solution est\ : .PP .Vb 3 \& while ($dna =~ /(\ew\ew\ew)*?TGA/g) { # remarquez le minimal *? \& print "Got a TGA stop codon at position ", pos $dna, "\en"; \& } .Ve .PP qui affichera\ : .PP .Vb 2 \& Got a TGA stop codon at position 18 \& Got a TGA stop codon at position 23 .Ve .PP La position 18 est correcte mais pas la position 23. Que s'est\-il passe\*' ? .PP Notre expression rationnelle fonctionne bien tant qu'il reste de bonnes correspondances. Puis l'expression rationnelle ne trouve plus de \f(CW\*(C`TGA\*(C'\fR bien synchronise\*' et re\*'essaie apre\*`s s'e\*^tre de\*'cale\*'e d'un caracte\*`re a\*` chaque fois. Ce n'est pas ce que nous voulons. La solution est l'utilisation de \f(CW\*(C`\eG\*(C'\fR pour ancrer notre expression rationnelle sur une limite de codon\ : .PP .Vb 3 \& while ($dna =~ /\eG(\ew\ew\ew)*?TGA/g) { \& print "Got a TGA stop codon at position ", pos $dna, "\en"; \& } .Ve .PP qui affiche\ : .PP .Vb 1 \& Got a TGA stop codon at position 18 .Ve .PP qui est la bonne re\*'ponse. Cet exemple illustre qu'il ne suffit pas de reconnai\*^tre ce que l'on cherche, il faut aussi rejeter ce qu'on ne veut pas. .PP \fIRecherche et remplacement\fR .IX Subsection "Recherche et remplacement" .PP Les expressions rationnelles jouent aussi un grand ro\*^le dans les ope\*'rations de recherche et remplacement en Perl. Une recherche/remplacement est accomplie via l'ope\*'rateur \f(CW\*(C`s///\*(C'\fR. La forme ge\*'ne\*'rale est \f(CW\*(C`s/regexp/remplacement/modificateurs\*(C'\fR avec l'application de tout ce que nous connaissons de\*'ja\*` sur les expressions rationnelles et les modificateurs. La partie \f(CW\*(C`remplacement\*(C'\fR est comme une chai\*^ne entre guillemets de Perl qui remplacera la partie de la chai\*^ne reconnue par l'expression rationnelle \f(CW\*(C`regexp\*(C'\fR. L'ope\*'rateur \f(CW\*(C`=~\*(C'\fR est aussi utilise\*' pour associer une chai\*^ne avec \f(CW\*(C`s///\*(C'\fR. Si on veut l'appliquer a\*` \f(CW$_\fR, on peut omettre \f(CW\*(C`$_\ =~\*(C'\fR\ . S'il y a correspondance, \f(CW\*(C`s///\*(C'\fR renvoie le nombre de substitutions effectue\*'es sinon il retourne faux. Voici quelques exemples\ : .PP .Vb 8 \& $x = "Time to feed the cat!"; \& $x =~ s/cat/hacker/; # $x contient "Time to feed the hacker!" \& if ($x =~ s/^(Time.*hacker)!$/$1 now!/) { \& $more_insistent = 1; \& } \& $y = "'quoted words'"; \& $y =~ s/^'(.*)'$/$1/; # suppression des apostrophes, \& # $y contient "quoted words" .Ve .PP Dans le dernier exemple, la chai\*^ne entie\*`re est reconnue mais seule la partie a\*` l'inte\*'rieur des apostrophes est dans un groupe. Avec l'ope\*'rateur \f(CW\*(C`s///\*(C'\fR, les variables \f(CW$1\fR, \f(CW$2\fR, etc. sont imme\*'diatement disponibles pour une utilisation dans l'expression de remplacement. Donc, nous utilisons \f(CW$1\fR pour remplacer la chai\*^ne entre apostrophes par ce qu'elle contient. Avec le modificateur global, \f(CW\*(C`s///g\*(C'\fR cherchera et remplacera toutes les occurrences de l'expression rationnelle dans la chai\*^ne\ : .PP .Vb 6 \& $x = "I batted 4 for 4"; \& $x =~ s/4/four/; # ne fait pas tout : \& # $x contient "I batted four for 4" \& $x = "I batted 4 for 4"; \& $x =~ s/4/four/g; # fait tout : \& # $x contient "I batted four for four" .Ve .PP Si vous pre\*'fe\*'rez 'regex' a\*` la place de 'regexp' dans ce tutoriel, vous pourriez utiliser le programme suivant pour les remplacer\ : .PP .Vb 9 \& % cat > simple_replace \& #!/usr/bin/perl \& $regexp = shift; \& $replacement = shift; \& while (<>) { \& s/$regexp/$replacement/go; \& print; \& } \& ^D \& \& % simple_replace regexp regex perlretut.pod .Ve .PP Dans \f(CW\*(C`simple_replace\*(C'\fR nous utilisons le modificateur \f(CW\*(C`s///g\*(C'\fR pour remplacer toutes les occurrences de l'expression rationnelle a\*` chaque ligne et le modificateur \f(CW\*(C`s///o\*(C'\fR pour compiler l'expression rationnelle une seule fois pour toutes. Comme avec \f(CW\*(C`simple_grep\*(C'\fR, les deux instructions \f(CW\*(C`print\*(C'\fR et \f(CW\*(C`s/$regexp/$replacement/go\*(C'\fR utilisent implicitement la variable \f(CW$_\fR. .PP Un modificateur spe\*'cifique a\*` l'ope\*'ration de recherche/remplacement est le modificateur d'e\*'valuation \f(CW\*(C`s///e\*(C'\fR. \f(CW\*(C`s///e\*(C'\fR ajoute un \f(CW\*(C`eval{...}\*(C'\fR autour de la chai\*^ne de remplacement et le re\*'sultat de cette e\*'valuation est substitue\*' a\*` la sous\-chai\*^ne mise en correspondance. \f(CW\*(C`s///e\*(C'\fR est utile si vous avez besoin de faire un traitement sur le texte a\*` remplacer. Cet exemple compte la fre\*'quence des lettres dans une ligne\ : .PP .Vb 4 \& $x = "Bill the cat"; \& $x =~ s/(.)/$chars{$1}++;$1/eg; # Le $1 final remplace le caracte\*`re par lui\-me\*^me \& print "frequency of '$_' is $chars{$_}\en" \& foreach (sort {$chars{$b} <=> $chars{$a}} keys %chars); .Ve .PP qui affiche\ : .PP .Vb 9 \& frequency of ' ' is 2 \& frequency of 't' is 2 \& frequency of 'l' is 2 \& frequency of 'B' is 1 \& frequency of 'c' is 1 \& frequency of 'e' is 1 \& frequency of 'h' is 1 \& frequency of 'i' is 1 \& frequency of 'a' is 1 .Ve .PP Comme pour l'ope\*'rateur \f(CW\*(C`m//\*(C'\fR, \f(CW\*(C`s///\*(C'\fR peut utiliser d'autres de\*'limiteurs comme \f(CW\*(C`s!!!\*(C'\fR ou \f(CW\*(C`s{}{}\*(C'\fR et me\*^me \f(CW\*(C`s{}//\*(C'\fR. Si les de\*'limiteurs sont des apostrophes \f(CW\*(C`s'''\*(C'\fR alors l'expression rationnelle et le remplacement sont traite\*'s comme des chai\*^nes entre apostrophes et aucune interpolation de variables n'est effectue\*'e. \f(CW\*(C`s///\*(C'\fR dans un contexte de liste retourne la me\*^me chose qu'en contexte scalaire, c'est a\*` dire le nombre de substitutions effectue\*'es. .PP \fIL'ope\*'rateur de de\*'coupage (split)\fR .IX Subsection "L'ope'rateur de de'coupage (split)" .PP La fonction \fB\f(CB\*(C`split\*(C'\fB \fR peut, elle aussi, utiliser un ope\*'rateur de mise en correspondance \f(CW\*(C`m//\*(C'\fR pour de\*'couper une chai\*^ne. \f(CW\*(C`split /regexp/, chaine, limite\*(C'\fR de\*'coupe la \f(CW\*(C`chaine\*(C'\fR en une liste de sous\-chai\*^nes et retourne cette liste. L'expression rationnelle \&\f(CW\*(C`regexp\*(C'\fR est utilise\*'e pour reconnai\*^tre la se\*'quence de caracte\*`res qui servira de se\*'parateur lors du de\*'coupage de \f(CW\*(C`chaine\*(C'\fR. La \f(CW\*(C`limite\*(C'\fR, si elle est pre\*'sente, indique le nombre maximal de morceaux lors du de\*'coupage. Par exemple, pour de\*'couper une chai\*^ne en mots, utilisez\ : .PP .Vb 4 \& $x = "Calvin and Hobbes"; \& @words = split /\es+/, $x; # $word[0] = 'Calvin' \& # $word[1] = 'and' \& # $word[2] = 'Hobbes' .Ve .PP Si l'expression rationnelle vide \f(CW\*(C`//\*(C'\fR est utilise\*'e alors l'expression rationnelle correspond partout et la chai\*^ne est de\*'coupe\*'e en caracte\*`res individuels. Si l'expression rationnelle contient des groupes alors la liste produite contient aussi les sous\-chai\*^nes reconnues par les groupes. Par exemple\ : .PP .Vb 12 \& $x = "/usr/bin/perl"; \& @dirs = split m!/!, $x; # $dirs[0] = '' \& # $dirs[1] = 'usr' \& # $dirs[2] = 'bin' \& # $dirs[3] = 'perl' \& @parts = split m!(/)!, $x; # $parts[0] = '' \& # $parts[1] = '/' \& # $parts[2] = 'usr' \& # $parts[3] = '/' \& # $parts[4] = 'bin' \& # $parts[5] = '/' \& # $parts[6] = 'perl' .Ve .PP Puisque le premier caracte\*`re de \f(CW$X\fR est reconnu par l'expression rationnelle, \f(CW\*(C`split\*(C'\fR ajoute un e\*'le\*'ment initial vide a\*` la liste. .PP Si vous avez tout lu jusqu'ici, fe\*'licitations ! Vous posse\*'dez maintenant tous les outils de base pour utiliser les expressions rationnelles afin de re\*'soudre de nombreux proble\*`mes de traitement de textes. Si c'est la premie\*`re fois que vous lisez ce tutoriel, vous devriez vous arre\*^ter ici et jouer quelques temps avec les expressions rationnelles... La Partie\ 2 concerne des aspects plus e\*'sote\*'riques des expressions rationnelles et ces concepts ne sont certainement pas ne\*'cessaires au de\*'but. .SH "Partie 2: au\-dela\*`" .IX Header "Partie 2: au-dela`" Bon, vous connaissez les bases des expressions rationnelles et vous voulez en savoir plus. Si la mise en correspondance d'une expression rationnelle est analogue a\*` une marche en fore\*^t alors les outils dont nous avons parle\*' dans la partie 1 sont la carte et le compas, des outils basiques que nous utilisons tout le temps. La plupart des outils de la partie 2 sont alors analogues a\*` un lance fuse\*'es e\*'clairantes ou a\*` un te\*'le\*'phone satellite. On ne les utilise pas tre\*`s souvent mais, en cas de besoin, ils sont irremplac\*,ables. .PP Ce qui suit pre\*'sente les fonctionnalite\*'s les plus avance\*'es, les moins utilise\*'es ou les plus e\*'sote\*'riques des expressions rationnelles de perl. Dans cette seconde partie, nous supposerons que vous e\*^tes a\*` l'aise avec les outils de base pour nous concentrer sur ces nouvelles fonctionnalite\*'s. .Sh "Les plus des caracte\*`res, des chai\*^nes et des classes de caracte\*`res" .IX Subsection "Les plus des caracte`res, des chai^nes et des classes de caracte`res" Il y a de nombreuses se\*'quences d'e\*'chappement et classes de caracte\*`res dont nous n'avons pas encore parle\*'. .PP Il existe plusieurs se\*'quences d'e\*'chappement qui convertissent les caracte\*`res ou les chai\*^nes entre majuscules et minuscules. \f(CW\*(C`\el\*(C'\fR et \&\f(CW\*(C`\eu\*(C'\fR convertissent le caracte\*`re suivant respectivement en minuscule ou en majuscule\ : .PP .Vb 4 \& $x = "perl"; \& $string =~ /\eu$x/; # reconnai\*^t 'Perl' dans $string \& $x = "M(rs?|s)\e\e."; # notez le double backslash \& $string =~ /\el$x/; # reconnai\*^t 'mr.', 'mrs.' et 'ms.', .Ve .PP \&\f(CW\*(C`\eL\*(C'\fR et \f(CW\*(C`\eU\*(C'\fR convertissent une sous\-chai\*^ne entie\*`re de\*'limite\*'e par \f(CW\*(C`\eL\*(C'\fR, \&\f(CW\*(C`\eU\*(C'\fR ou \f(CW\*(C`\eE\*(C'\fR en minuscule ou majuscule\ : .PP .Vb 4 \& $x = "This word is in lower case:\eL SHOUT\eE"; \& $x =~ /shout/; # correspond \& $x = "I STILL KEYPUNCH CARDS FOR MY 360" \& $x =~ /\eUkeypunch/; # correspond .Ve .PP S'il n'y a pas de \f(CW\*(C`\eE\*(C'\fR, la changement de casse a lieu jusqu'a\*` la fin de la chai\*^ne. Les expressions rationnelles \f(CW\*(C`\eL\eu$word\*(C'\fR ou \&\f(CW\*(C`\eu\eL$word\*(C'\fR convertissent le premier caracte\*`re de \f(CW$word\fR en majuscule et les autres caracte\*`res en minuscules. .PP Les caracte\*`res de contro\*^le peuvent e\*^tre code\*'s via \f(CW\*(C`\ec\*(C'\fR. Le caracte\*`re control-z sera mis en correspondance avec \f(CW\*(C`\ecZ\*(C'\fR. La se\*'quence d'e\*'chappement \f(CW\*(C`\eQ\*(C'\fR...\f(CW\*(C`\eE\*(C'\fR prote\*`ge la plupart des caracte\*`res non\-alphabe\*'tiques. Par exemple : .PP .Vb 2 \& $x = "\eQThat !^*&%~& cat!"; \& $x =~ /\eQ!^*&%~&\eE/; # correspond .Ve .PP Les caracte\*`res \f(CW\*(C`$\*(C'\fR et \f(CW\*(C`@\*(C'\fR ne sont pas prote\*'ge\*'s donc les variables peuvent encore e\*^tre interpole\*'es. .PP Avec Perl 5.6.0, les expressions rationnelles peuvent ge\*'rer plus que le jeu de caracte\*`res \s-1ASCII\s0. Perl supporte maintenant l'\fBUnicode\fR, un standard pour encoder les caracte\*`res de la plupart des langues. Unicode permet cela en autorisant un encodage des caracte\*`res sur plusieurs octets. Perl utilise l'encodage \s-1UTF\-8\s0 dans lequel les caracte\*`res \s-1ASCII\s0 sont encore encode\*'s sur un octet mais ou\*` les caracte\*`res plus grand que \f(CW\*(C`chr(127)\*(C'\fR peuvent e\*^tre code\*'s sur deux ou plusieurs octets. .PP Quelles conse\*'quences sur les expressions rationnelles ? Les utilisateurs d'expressions rationnelles n'ont pas besoin de connai\*^tre la repre\*'sentation interne des chai\*^nes de perl. Par contre, il faut qu'ils sachent 1) comment repre\*'senter les caracte\*`res Unicode dans une expression rationnelle et 2) quand une ope\*'ration de mise en correspondance traitera une chai\*^ne comme une se\*'quence d'octets (l'ancien mode) ou comme une se\*'quence de caracte\*`res Unicode (le nouveau mode). La re\*'ponse a\*` la question 1) est que les caracte\*`res Unicode plus grand que \f(CW\*(C`chr(127)\*(C'\fR peuvent e\*^tre repre\*'sente\*'s en utilisant la notation \&\f(CW\*(C`\ex{hex}\*(C'\fR ou\*` \f(CW\*(C`hex\*(C'\fR est un entier hexade\*'cimal\ : .PP .Vb 1 \& /\ex{263a}/; # correspond a\*` l'e\*'moticon souriant d'Unicode :) .Ve .PP Les caracte\*`res Unicode dans l'intervalle 128\-255 utilisent deux chiffres hexade\*'cimaux avec des accolades\ : \f(CW\*(C`\ex{ab}\*(C'\fR. Remarquez la diffe\*'rence avec \f(CW\*(C`\exab\*(C'\fR qui est juste un octet en hexade\*'cimal sans aucune signification Unicode. .PP \&\fB\s-1NOTE\s0\fR: en Perl 5.6.0 il fallait ajouter la directive \f(CW\*(C`use utf8\*(C'\fR pour activer les fonctionnalite\*'s Unicode. Ce n'est plus ne\*'cessaire\ : la quasi totalite\*' des fonctionnalite\*'s Unicode ne ne\*'cessitent plus la directive ou pragma \f(CW\*(C`utf8\*(C'\fR. (Le seul cas ou\*` cela reste ne\*'cessaire est celui ou\*` votre script Perl lui\-me\*^me est e\*'crit en Unicode encode\*' en \s-1UTF\-8\s0.) .PP Se souvenir de la se\*'quence hexade\*'cimale d'un caracte\*`re Unicode ou de\*'coder les se\*'quences hexade\*'cimales d'un autre dans une expression rationnelle est presque aussi fun que de coder en langage machine. Un autre moyen de spe\*'cifier des caracte\*`res Unicode est d'utiliser des \&\fBcaracte\*`res\ nomme\*'s\fR\ via la se\*'quence d'e\*'chappement \&\f(CW\*(C`\eN{nom}\*(C'\fR. \f(CW\*(C`nom\*(C'\fR est le nom d'un caracte\*`re Unicode comme spe\*'cifie\*' dans le standard Unicode. Par exemple, si vous voulez repre\*'senter ou reconnai\*^tre le signe astrologique de la plane\*`te Mercure, vous pourriez utiliser\ : .PP .Vb 4 \& use charnames ":full"; # utilise les caracte\*`res nomme\*'s \& # avec les noms Unicode complet \& $x = "abc\eN{MERCURY}def"; \& $x =~ /\eN{MERCURY}/; # correspond .Ve .PP Il est aussi possible d'utiliser les noms courts ou restreints a\*` certains alphabets\ : .PP .Vb 2 \& use charnames ':full'; \& print "\eN{GREEK SMALL LETTER SIGMA} is called sigma.\en"; \& \& use charnames ":short"; \& print "\eN{greek:Sigma} is an upper\-case sigma.\en"; \& \& use charnames qw(greek); \& print "\eN{sigma} is Greek sigma\en"; .Ve .PP Une liste de tous les noms complets est disponible dans le fichier Names.txt du re\*'pertoire lib/perl5/5.x.x/unicode. .PP La re\*'ponse au point 2), depuis la version 5.6.0, est que si une expression rationnelle contient des caracte\*`res Unicode alors la chai\*^ne est conside\*'re\*'e comme une se\*'quence de caracte\*`res Unicode. Sinon, la chai\*^ne est explore\*'e comme une suite d'octets. Si la chai\*^ne doit e\*^tre vue comme une se\*'quence de caracte\*`res Unicode et que vous voulez reconnai\*^tre un seul octet, vous pouvez utiliser la se\*'quence d'e\*'chappement \f(CW\*(C`\eC\*(C'\fR. \f(CW\*(C`\eC\*(C'\fR est une classe de caracte\*`res comme \f(CW\*(C`.\*(C'\fR sauf qu'elle reconnai\*^t \fIn'importe\fR quel octet (0\-255). Donc\ : .PP .Vb 7 \& use charnames ":full"; # utilisation des noms Unicode longs \& $x = "a"; \& $x =~ /\eC/; # correspond a\*` 'a', mange un octet \& $x = ""; \& $x =~ /\eC/; # pas de correspondance, aucun octet consomme\*' \& $x = "\eN{MERCURY}"; # caracte\*`re Unicode sur deux octets \& $x =~ /\eC/; # correspond, mais dangeureux .Ve .PP La dernie\*`re expression rationnelle correspond mais c'est dangereux parce que la position \fIcaracte\*`re\fR dans la chai\*^ne n'est plus synchronise\*'e avec la position \fIoctet\fR. Cela engendre le message d'avertissement 'Malformed \s-1UTF\-8\s0 character' ('Caracte\*`re \s-1UTF\-8\s0 mal forme\*''). Un \f(CW\*(C`\eC\*(C'\fR est pluto\*^t indique\*' pour reconnai\*^tre des donne\*'es binaires dans une chai\*^ne mixant du binaire et des caracte\*`res Unicode. .PP Revoyons maintenant les classes de caracte\*`res. Comme pour les caracte\*`res Unicode, il existe des noms pour les classes de caracte\*`res Unicode repre\*'sente\*'es par la se\*'quence d'e\*'chappement \f(CW\*(C`\ep{nom}\*(C'\fR. Leur ne\*'gation \f(CW\*(C`\eP{nom}\*(C'\fR existe aussi. Par exemple, pour reconnai\*^tre les caracte\*`res majuscules et minuscules\ : .PP .Vb 6 \& use charnames ":full"; # utilisation des noms Unicode longs \& $x = "BOB"; \& $x =~ /^\ep{IsUpper}/; # correspond, les caracte\*`res majuscules \& $x =~ /^\eP{IsUpper}/; # pas de correspondance, les caracte\*`res sans majuscules \& $x =~ /^\ep{IsLower}/; # pas de correspondance, les caracte\*`res minuscules \& $x =~ /^\eP{IsLower}/; # correspond, les caracte\*`res sans les minuscules .Ve .PP Voici les associations entre quelques noms de classes Perl et les classes traditionnelles Unicode\ : .PP .Vb 1 \& Nom de classe Perl Nom de classe Unicode ou expression rationnelle \& \& IsAlpha /^[LM]/ \& IsAlnum /^[LMN]/ \& IsASCII $code <= 127 \& IsCntrl /^C/ \& IsBlank $code =~ /^(0020|0009)$/ || /^Z[^lp]/ \& IsDigit Nd \& IsGraph /^([LMNPS]|Co)/ \& IsLower Ll \& IsPrint /^([LMNPS]|Co|Zs)/ \& IsPunct /^P/ \& IsSpace /^Z/ || ($code =~ /^(0009|000A|000B|000C|000D)$/ \& IsSpacePerl /^Z/ || ($code =~ /^(0009|000A|000C|000D|0085|2028|2029)$/ \& IsUpper /^L[ut]/ \& IsWord /^[LMN]/ || $code eq "005F" \& IsXDigit $code =~ /^00(3[0\-9]|[46][1\-6])$/ .Ve .PP Vous pouvez aussi utiliser les noms officiels des classes Unicode gra\*^ce a\*` \f(CW\*(C`\ep\*(C'\fR et \f(CW\*(C`\eP\*(C'\fR comme dans \f(CW\*(C`\ep{L}\*(C'\fR pour les 'lettres' Unicode, \&\f(CW\*(C`\ep{Lu}\*(C'\fR pour les lettres minuscules ou \f(CW\*(C`\eP{Nd}\*(C'\fR pour les non\-chiffres. Si \f(CW\*(C`nom\*(C'\fR est compose\*' d'une seule lettre, les accolades peuvent e\*^tre omises. Par exemple \f(CW\*(C`\epM\*(C'\fR est la classe de caracte\*`res Unicode 'marks' pour les accents. Pour la liste comple\*`te, voir perlunicode. .PP Unicode est de\*'coupe\*' en plusieurs sous-ensembles de caracte\*`res que vous pouvez tester par \f(CW\*(C`\ep{In...}\*(C'\fR (dans) et \f(CW\*(C`\eP{In...}\*(C'\fR (hors de). Par exemple \f(CW\*(C`\ep{Latin}\*(C'\fR, \f(CW\*(C`\ep{Greek}\*(C'\fR ou \f(CW\*(C`\eP{Katakana}\*(C'\fR. Pour une liste comple\*`te, voir perlunicode. .PP \&\f(CW\*(C`\eX\*(C'\fR est une abre\*'viation pour la se\*'quence de classes de caracte\*`res qui contient les 'se\*'quences Unicode de caracte\*`res combine\*'s'. Une \&'se\*'quence de caracte\*`res combine\*'s' est un caracte\*`re de base suivi d'un certain nombre de caracte\*`res de combinaison. Un exemple de caracte\*`res de combinaison est un accent. En utilisant les noms Unicode longs, \&\f(CW\*(C`A\ +\ COMBINING\ RING\*(C'\fR\ est une se\*'quence de caracte\*`res combine\*'s avec \&\f(CW\*(C`A\*(C'\fR comme caracte\*`re de base et \f(CW\*(C`COMBINING\ RING\*(C'\fR\ comme caracte\*`re de combinaison et cette se\*'quence repre\*'sente, en Danois, un A avec un cercle au-dessus comme dans le mot Angstroem. \f(CW\*(C`\eX\*(C'\fR est e\*'quivalent a\*` \&\f(CW\*(C`\ePM\epM*\*(C'\fR qui signifie un caracte\*`re non-marque e\*'ventuellement suivi d'une se\*'rie de caracte\*`res marques. .PP Pour obtenir les informations les plus re\*'centes et comple\*`tes concernant Unicode, consultez la norme Unicode ou le sit web du consortium Unicode http://www.unicode.org/. .PP Et comme si toutes ces classes ne suffisaient pas, Perl de\*'finit aussi des classes de caracte\*`res de style \s-1POSIX\s0. Elles sont de la forme \&\f(CW\*(C`[:nom:]\*(C'\fR ou\*` \f(CW\*(C`nom\*(C'\fR est le nom d'une classe \s-1POSIX\s0. Les classes \s-1POSIX\s0 sont \f(CW\*(C`alpha\*(C'\fR, \f(CW\*(C`alnum\*(C'\fR, \f(CW\*(C`ascii\*(C'\fR, \f(CW\*(C`cntrl\*(C'\fR, \f(CW\*(C`digit\*(C'\fR, \f(CW\*(C`graph\*(C'\fR, \&\f(CW\*(C`lower\*(C'\fR, \f(CW\*(C`print\*(C'\fR, \f(CW\*(C`punct\*(C'\fR, \f(CW\*(C`space\*(C'\fR, \f(CW\*(C`upper\*(C'\fR et \f(CW\*(C`xdigit\*(C'\fR plus les deux extensions \f(CW\*(C`word\*(C'\fR (une extension Perl pour reconnai\*^tre \f(CW\*(C`\ew\*(C'\fR) et \&\f(CW\*(C`blank\*(C'\fR (une extension \s-1GNU\s0). Si \f(CW\*(C`utf8\*(C'\fR est actif alors ces classes sont de\*'finies de la me\*^me manie\*`re que les classes Unicode correspondantes\ : \f(CW\*(C`[:upper:]\*(C'\fR est la me\*^me chose que \&\f(CW\*(C`\ep{IsUpper}\*(C'\fR, etc. Les classes de caracte\*`res \s-1POSIX\s0, par contre, ne ne\*'cessitent pas l'utilisation de \f(CW\*(C`utf8\*(C'\fR. Les classes \f(CW\*(C`[:digit:]\*(C'\fR, \&\f(CW\*(C`[:word:]\*(C'\fR et \f(CW\*(C`[:space:]\*(C'\fR correspondent aux classes familie\*`res \&\f(CW\*(C`\ed\*(C'\fR, \f(CW\*(C`\ew\*(C'\fR et \f(CW\*(C`\es\*(C'\fR. Pour obtenir la ne\*'gation d'une classe \s-1POSIX\s0, placez un \f(CW\*(C`^\*(C'\fR devant son nom comme dans \f(CW\*(C`[:^digit:]\*(C'\fR qui correspond a\*` \f(CW\*(C`\eD\*(C'\fR ou, avec \f(CW\*(C`utf8\*(C'\fR, a\*` \f(CW\*(C`\eP{IsDigit}\*(C'\fR. Les classes Unicode et \&\s-1POSIX\s0 peuvent e\*^tre utilise\*'es comme \f(CW\*(C`\ed\*(C'\fR, en sachant que les classes \&\s-1POSIX\s0 ne sont accessibles qu'a\*` l'inte\*'rieur d'une classe de caracte\*`res\ : .PP .Vb 7 \& /\es+[abc[:digit:]xyz]\es*/; # reconnai\*^t a,b,c,x,y,z ou un chiffre \& /^=item\es[[:digit:]]/; # reconnai\*^t '=item', \& # suivi d'un espace et d'un chiffre \& use charnames ":full"; \& /\es+[abc\ep{IsDigit}xyz]\es+/; # reconnai\*^t a,b,c,x,y,z ou un chiffre \& /^=item\es\ep{IsDigit}/; # reconnai\*^t '=item', \& # suivi d'un espace et d'un chiffre .Ve .PP C'est tout pour les caracte\*`res et les classes de caracte\*`res. .Sh "Compilation et stockage d'expressions rationnelles" .IX Subsection "Compilation et stockage d'expressions rationnelles" Dans la partie 1, nous avons parle\*' du modificateur \f(CW\*(C`//o\*(C'\fR qui compile une expression rationnelle une seule fois. Cela sugge\*`re qu'une expression rationnelle compile\*'e est une sorte de structure de donne\*'es qui peut e\*^tre stocke\*'e une fois et utilise\*'e plusieurs fois. L'ope\*'rateur d'expression rationnelle \f(CW\*(C`qr//\*(C'\fR fait exactement cela\ : \&\f(CW\*(C`qr/chaine/\*(C'\fR compile la chai\*^ne \f(CW\*(C`chaine\*(C'\fR en tant qu'expression rationnelle et transforme le re\*'sultat en quelque chose qui peut e\*^tre affecte\*'e a\*` une variable. .PP .Vb 1 \& $reg = qr/foo+bar?/; # reg contient une expression rationnelle compile\*'e .Ve .PP Puis \f(CW$reg\fR peut e\*^tre utilise\*'e en tant qu'expression rationnelle\ : .PP .Vb 3 \& $x = "fooooba"; \& $x =~ $reg; # est reconnu, exactement comme /foo+bar?/ \& $x =~ /$reg/; # idem, sous une forme diffe\*'rente .Ve .PP \&\f(CW$reg\fR peut aussi e\*^tre utilise\*'e au sein d'une expression rationnelle plus grande\ : .PP .Vb 1 \& $x =~ /(abc)?$reg/; # est encore reconnue .Ve .PP Comme avec l'ope\*'rateur de recherche de correspondances, l'ope\*'rateur d'expression rationnelle peut utiliser diffe\*'rents de\*'limiteurs tels \&\f(CW\*(C`qr!!\*(C'\fR, \f(CW\*(C`qr{}\*(C'\fR ou \f(CW\*(C`qr~~\*(C'\fR. Le de\*'limiteur apostrophe (\f(CW\*(C`qr''\*(C'\fR) supprime l'interpolation des variables. .PP La pre\*'\-compilation des expressions rationnelles est utile pour des mises en correspondances dynamiques qui ne ne\*'cessitent pas une recompilation a\*` chaque fois. En utilisant des expressions rationnelles pre\*'\-compile\*'es, le programme \f(CW\*(C`simple_grep\*(C'\fR peut e\*^tre transforme\*' en un programme qui cherche plusieurs expressions rationnelles\ : .PP .Vb 4 \& % cat > multi_grep \& #!/usr/bin/perl \& # multi_grep \- match any of regexps \& # usage: multi_grep regexp1 regexp2 ... file1 file2 ... \& \& $number = shift; \& $regexp[$_] = shift foreach (0..$number\-1); \& @compiled = map qr/$_/, @regexp; \& while ($line = <>) { \& foreach $pattern (@compiled) { \& if ($line =~ /$pattern/) { \& print $line; \& last; # correspondance trouve\*'e, on passe a\*` la ligne suivante \& } \& } \& } \& ^D \& \& % multi_grep 2 last for multi_grep \& $regexp[$_] = shift foreach (0..$number\-1); \& foreach $pattern (@compiled) { \& last; .Ve .PP Le stockage des expressions rationnelles pre\*'\-compile\*'es dans le tableau \&\f(CW@compiled\fR nous permet de faire une boucle sur les expressions rationnelles sans les recompiler. On y gagne en flexibilite\*' sans sacrifier la vitesse. .Sh "Commentaires et modificateurs inte\*'gre\*'s dans une expression rationnelle" .IX Subsection "Commentaires et modificateurs inte'gre's dans une expression rationnelle" A\*` partir d'ici, nous allons parler des motifs e\*'tendus de Perl. Ce sont des extensions de la syntaxe traditionnelle des expressions rationnelles qui fournissent de nouveaux outils utiles pour la recherche de motifs. Nous avons de\*'ja\*` vu des extensions telles que les quantificateurs minimaux \f(CW\*(C`??\*(C'\fR, \f(CW\*(C`*?\*(C'\fR, \f(CW\*(C`+?\*(C'\fR, \f(CW\*(C`{n,m}?\*(C'\fR et \&\f(CW\*(C`{n,}?\*(C'\fR. Les autres extensions sont toutes de la forme \f(CW\*(C`(?car...)\*(C'\fR ou\*` \f(CW\*(C`car\*(C'\fR est un caracte\*`re qui de\*'termine le type de l'extension. .PP La premie\*`re extension est un commentaire \f(CW\*(C`(?#texte)\*(C'\fR. Cela permet d'inclure un commentaire dans l'expression rationnelle sans modifier sa signification. Le commentaire ne doit pas contenir de parenthe\*`se fermante dans son texte. Un exemple\ : .PP .Vb 1 \& /(?# reconnai\*^t un entier:)[+\-]?\ed+/; .Ve .PP Ce style de commentaires a e\*'te\*' largement ame\*'liore\*' gra\*^ce au modificateur \f(CW\*(C`//x\*(C'\fR qui permet des commentaires beaucoup plus libres et simples. .PP Les modificateurs \f(CW\*(C`//i\*(C'\fR, \f(CW\*(C`//m\*(C'\fR, \f(CW\*(C`//s\*(C'\fR et \f(CW\*(C`//x\*(C'\fR peuvent eux aussi e\*^tre inte\*'gre\*'s dans une expression rationnelle en utilisant \f(CW\*(C`(?i)\*(C'\fR, \&\f(CW\*(C`(?m)\*(C'\fR, \f(CW\*(C`(?s)\*(C'\fR et \f(CW\*(C`(?x)\*(C'\fR. Par exemple\ : .PP .Vb 7 \& /(?i)yes/; # reconnai\*^t 'yes' sans tenir compte de la casse \& /yes/i; # la me\*^me chose \& /(?x)( \& [+\-]? # un signe optionnel \& \ed+ # les chiffres \& ) \& /x; .Ve .PP Les modificateurs inclus ont deux avantages importants sur les modificateurs habituels. Tout d'abord, ils permettent de spe\*'cifier une combinaison de modificateurs diffe\*'rente pour \fIchaque\fR partie de l'expression rationnelle. C'est pratique pour mettre en correspondance un tableau d'expressions rationnelles qui ont des modificateurs diffe\*'rents\ : .PP .Vb 8 \& $pattern[0] = '(?i)doctor'; \& $pattern[1] = 'Johnson'; \& ... \& while (<>) { \& foreach $patt (@pattern) { \& print if /$patt/; \& } \& } .Ve .PP Ensuite parce que les modificateurs inclus n'agissent que sur le groupe dans lequel ils apparaissent. Donc, le regroupement peut e\*^tre utiliser pour XlocaliserX l'effet des modificateurs\ : .PP .Vb 1 \& /Answer: ((?i)yes)/; # reconnai\*^t 'Answer: yes', 'Answer: YES', etc. .Ve .PP Les modificateurs inclus peuvent aussi annuler des modificateurs de\*'ja\*` pre\*'sents en utilisant par exemple \f(CW\*(C`(?\-i)\*(C'\fR. Les modificateurs peuvent e\*^tre combine\*'s en une seule expression comme \f(CW\*(C`(?s\-i)\*(C'\fR qui active le mode simple ligne et annule l'insensibilite\*' a\*` la casse. .Sh "Les regroupements sans me\*'morisation" .IX Subsection "Les regroupements sans me'morisation" Nous avons fait remarquer dans la partie 1 qu'un regroupement \f(CW\*(C`()\*(C'\fR avait deux fonctions\ : 1) regrouper plusieurs e\*'le\*'ments d'une expression rationnelle en une seule entite\*' et 2) extraire ou me\*'moriser la sous\-chai\*^ne reconnue par le regroupement. Les regroupements sans me\*'morisation, note\*'s \f(CW\*(C`(?:regexp)\*(C'\fR, effectuent un regroupement qui peut e\*^tre traite\*' comme une seule entite\*' mais n'extraient pas la chai\*^ne correspondante et ne la me\*'morise pas dans les variables \f(CW$1\fR, etc. Les deux types de regroupements (avec ou sans me\*'morisation) peuvent coexister dans une me\*^me expression rationnelle. Puisqu'il n'y a pas d'extraction, les regroupements sans me\*'morisation sont plus rapides que les regroupements avec me\*'morisation. Les regroupements sans me\*'morisation sont aussi pratiques pour choisir exactement les parties de l'expression rationnelle qui seront affecte\*'es aux variables\ : .PP .Vb 2 \& # reconnai\*^t un nombre, $1\-$4 sont positionne\*'es, mais nous ne voulons que $1 \& /([+\-]?\e *(\ed+(\e.\ed*)?|\e.\ed+)([eE][+\-]?\ed+)?)/; \& \& # reconnai\*^t un nombre plus rapidement , seule $1 est positionne\*'e \& /([+\-]?\e *(?:\ed+(?:\e.\ed*)?|\e.\ed+)(?:[eE][+\-]?\ed+)?)/; \& \& # reconnai\*^t un nombre, on obtient $1 = nombre complet, $2 = exposant \& /([+\-]?\e *(?:\ed+(?:\e.\ed*)?|\e.\ed+)(?:[eE]([+\-]?\ed+))?)/; .Ve .PP Les regroupements sans me\*'morisation sont aussi pratiques pour supprimer les effets indirects nuisibles lors d'une ope\*'ration de de\*'coupage (via 'split')\ : .PP .Vb 3 \& $x = '12a34b5'; \& @num = split /(a|b)/, $x; # @num = ('12','a','34','b','5') \& @num = split /(?:a|b)/, $x; # @num = ('12','34','5') .Ve .PP Les regroupements sans me\*'morisation peuvent eux aussi inclure des modificateurs\ : \f(CW\*(C`(?i\-m:regexp)\*(C'\fR est un regroupement sans me\*'morisation qui reconnai\*^t \f(CW\*(C`regexp\*(C'\fR sans tenir compte de la casse et en de\*'sactivant le mode multi\-lignes. .Sh "Regarder en arrie\*`re et regarder en avant" .IX Subsection "Regarder en arrie`re et regarder en avant" Cette section pre\*'sente les assertions permettant de regarder en arrie\*`re ou en avant. Tout d'abord quelques petits e\*'le\*'ments d'introduction. .PP Dans les expressions rationnelles en Perl, la plupart des e\*'le\*'ments \&'consomment' une certaine quantite\*' de la chai\*^ne avec lesquels ils sont mis en correspondance. Par exemple, l'e\*'le\*'ment \f(CW\*(C`[abc]\*(C'\fR consomme un caracte\*`re de la chai\*^ne lorsqu'il est reconnu, dans le sens ou\*` Perl avance au caracte\*`re suivant dans la chai\*^ne apre\*`s la mise en correspondance. Il existe certains e\*'le\*'ments, par contre, qui ne consomment aucun caracte\*`re (il ne change pas la position) lorsqu'ils sont reconnus. Les exemples que nous avons de\*'ja\*` vus sont des ancres. L'ancre \f(CW\*(C`^\*(C'\fR reconnai\*^t le de\*'but de ligne mais ne consomme aucun caracte\*`re. De me\*^me, l'ancre de bordure de mot \f(CW\*(C`\eb\*(C'\fR est reconnue entre un caracte\*`re mot et un caracte\*`re non-mot mais elle ne consomme aucun caracte\*`re. Ces ancres sont des exemples d'assertions de longueur nulle. X De longueur nulle X parce qu'elles ne consomment aucun caracte\*`re et X assertion X parce qu'elles testent une proprie\*'te\*' de la chai\*^ne. Dans le contexte de notre analogie avec la traverse\*'e d'une fore\*^t, la plupart des e\*'le\*'ments des expressions rationnelles nous font avancer le long du chemin alors que les ancres nous arre\*^tent pour regarder autour de nous. Si l'environnement local convient, nous pouvons continuer. Sinon, il faut effectuer un retour arrie\*`re. .PP Ve\*'rifier l'environnement peut impliquer un regard en avant, en arrie\*`re ou les deux. \f(CW\*(C`^\*(C'\fR regarde en arrie\*`re pour ve\*'rifier qu'il n'y a aucun caracte\*`re avant. \f(CW\*(C`$\*(C'\fR regarde en avant pour ve\*'rifier qu'il n'y a pas de caracte\*`re apre\*`s. \f(CW\*(C`\eb\*(C'\fR regarde en avant et en arrie\*`re pour ve\*'rifier que les deux caracte\*`res sont de natures diffe\*'rentes (mot et non\-mot). .PP Les assertions en avant et en arrie\*`re sont des ge\*'ne\*'ralisations du concept d'ancres. Ce sont des assertions de longueur nulle qui nous permettent de spe\*'cifier les caracte\*`res que nous voulons. L'assertion de regard en avant est note\*'e \f(CW\*(C`(?=regexp)\*(C'\fR alors que l'assertion de regard en arrie\*`re est note\*'e \f(CW\*(C`(?<=fixed\-regexp)\*(C'\fR. Voici quelques exemples\ : .PP .Vb 8 \& $x = "I catch the housecat 'Tom\-cat' with catnip"; \& $x =~ /cat(?=\es+)/; # reconnai\*^t 'cat' dans 'housecat' \& @catwords = ($x =~ /(?<=\es)cat\ew+/g); # correspond avec \& # $catwords[0] = 'catch' \& # $catwords[1] = 'catnip' \& $x =~ /\ebcat\eb/; # reconnai\*^t 'cat' dans 'Tom\-cat' \& $x =~ /(?<=\es)cat(?=\es)/; # pas de correspondance; pas de 'cat' isole\*' \& # au milieu de $x .Ve .PP Notez que les parenthe\*`ses dans \f(CW\*(C`(?=regexp)\*(C'\fR et \f(CW\*(C`(?<=regexp)\*(C'\fR sont sans me\*'morisation puisque ce sont des assertions de longueur nulle. Donc, dans le deuxie\*`me exemple, les sous\-chai\*^nes capture\*'es sont celles reconnues par l'expression rationnelle comple\*`te. Les assertions en avant \f(CW\*(C`(?=regexp)\*(C'\fR peuvent reconnai\*^tre une expression rationnelle quelconque. Par contre, les assertions en arrie\*`re \f(CW\*(C`(?<=fixed\-regexp)\*(C'\fR ne fonctionnent que pour des expressions rationnelles de longueur fixe (dont le nombre de caracte\*`res est fixe\*'). Donc \f(CW\*(C`(?<=(ab|bc))\*(C'\fR est correct mais pas \&\f(CW\*(C`(?<=(ab)*)\*(C'\fR. Les ne\*'gations de ces assertions se notent respectivement \f(CW\*(C`(?!regexp)\*(C'\fR et \f(CW\*(C`(?regexp)\*(C'\fR. Pour illustrer leur comportement, conside\*'rons tout d'abord une expression rationnelle ordinaire\ : .PP .Vb 2 \& $x = "ab"; \& $x =~ /a*ab/; # correspondance .Ve .PP Il y a e\*'videmment correspondance mais lors de la reconnaissance, la sous-expression \f(CW\*(C`a*\*(C'\fR consomme d'abord le \f(CW\*(C`a\*(C'\fR. Ce faisant, elle empe\*^che la reconnaissance de l'expression rationnelle globale. Donc, apre\*`s retour arrie\*`re, \f(CW\*(C`a*\*(C'\fR laisse le \f(CW\*(C`a\*(C'\fR et reconnai\*^t la chai\*^ne vide. Ici, ce que \f(CW\*(C`a*\*(C'\fR a reconnu est \fIde\*'pendant\fR de ce qui est reconnu par le reste de l'expression rationnelle. .PP En revanche, conside\*'rons l'expression rationnelle avec une sous-expression inde\*'pendante\ : .PP .Vb 1 \& $x =~ /(?>a*)ab/; # pas de correspondance .Ve .PP La sous-expression inde\*'pendante \f(CW\*(C`(?>a*)\*(C'\fR ne tiens pas compte du reste de l'expression rationnelle et donc consomme le \f(CW\*(C`a\*(C'\fR. Le reste de l'expression rationnelle \f(CW\*(C`ab\*(C'\fR ne peut plus trouver de correspondances. Puisque \f(CW\*(C`(?>a*)\*(C'\fR est inde\*'pendante, il n'y a pas de retour arrie\*`re et la sous-expression inde\*'pendante ne rela\*^che pas son \f(CW\*(C`a\*(C'\fR. Donc l'expression rationnelle globale n'est pas reconnue. On observe un comportement similaire avec deux expressions rationnelles comple\*`tement inde\*'pendantes\ : .PP .Vb 3 \& $x = "ab"; \& $x =~ /a*/g; # est reconnue, consomme le 'a' \& $x =~ /\eGab/g; # pas de correspondance, plus de 'a' disponible .Ve .PP Ici \f(CW\*(C`//g\*(C'\fR et \f(CW\*(C`\eG\*(C'\fR cre\*'ent un point de non-retour entre les deux expressions rationnelles. Les expressions rationnelles avec des sous-expressions inde\*'pendantes font un peu la me\*^me chose en plac\*,ant un point de non-retour apre\*`s la reconnaissance d'une sous-expression inde\*'pendante. .PP Cette possibilite\*' de blocage du retour arrie\*`re gra\*^ce aux sous-expressions inde\*'pendantes est tre\*`s pratique. Supposons que nous voulons reconnai\*^tre une chai\*^ne non-vide entre parenthe\*`ses (pouvant contenir elle\-me\*^me un niveau de parenthe\*`ses). L'expression rationnelle suivante fonctionnera\ : .PP .Vb 2 \& $x = "abc(de(fg)h"; # parenthe\*`se non referme\*'e \& $x =~ /\e( ( [^()]+ | \e([^()]*\e) )+ \e)/x; .Ve .PP L'expression rationnelle reconnai\*^t une parenthe\*`se ouvrante, une ou plusieurs occurrences d'une alternative et une parenthe\*`se fermante. La premie\*`re branche de l'alternative \f(CW\*(C`[^()]+\*(C'\fR reconnai\*^t un sous\-chai\*^ne sans parenthe\*`se et la seconde branche \f(CW\*(C`\e([^()]*\e)\*(C'\fR reconnai\*^t une sous\-chai\*^ne entoure\*'e de parenthe\*`ses. Cette expression rationnelle est malheureusement pathologique\ : elle contient des quantificateurs imbrique\*'s de la forme \f(CW\*(C`(a+|b)+\*(C'\fR. Nous avons explique\*' dans la partie 1 pourquoi une telle imbrication impliquait un temps d'exe\*'cution exponentiel en cas de non\-reconnaissance. Pour pre\*'venir cette explosion combinatoire, nous devons empe\*^cher les retours arrie\*`re inutiles quelque part. On peut y arriver en incluant le quantificateur interne dans une sous-expression inde\*'pendante\ : .PP .Vb 1 \& $x =~ /\e( ( (?>[^()]+) | \e([^()]*\e) )+ \e)/x; .Ve .PP Ici, \f(CW\*(C`(?>[^()]+)\*(C'\fR interrompt le partitionnement combinatoire de la chai\*^ne en consommant la partie la plus grande possible de la chai\*^ne sans permettre le retour arrie\*`re. Donc, la non-reconnaissance sera de\*'tecte\*'e beaucoup plus rapidement. .Sh "Les expressions conditionnelles" .IX Subsection "Les expressions conditionnelles" Une \fBexpression\ conditionnelle\fR\ est une forme d'instruction si-alors-sinon qui permet de choisir entre deux motifs a\*` reconnai\*^tre selon une condition. Il existe deux types d'expressions conditionnelles\ : \f(CW\*(C`(?(condition)motif\-oui)\*(C'\fR et \&\f(CW\*(C`(?(condition)motif\-oui|motif\-non)\*(C'\fR. \f(CW\*(C`(?(condition)motif\-oui)\*(C'\fR agit comme une instruction \f(CW'if\ ()\ {}'\fR\ en Perl. Si la \f(CW\*(C`condition\*(C'\fR est vraie, le \f(CW\*(C`motif\-oui\*(C'\fR doit e\*^tre reconnu. Si la \f(CW\*(C`condition\*(C'\fR est fausse, le \f(CW\*(C`motif\-oui\*(C'\fR n'est pas pris en compte et perl passe a\*` l'e\*'le\*'ment suivant dans l'expression rationnelle. La seconde forme est comme une instruction \f(CW'if\ ()\ {}\ else\ {}'\fR\ en Perl. Si la \&\f(CW\*(C`condition\*(C'\fR est vraie le \f(CW\*(C`motif\-oui\*(C'\fR doit e\*^tre reconnu sinon c'est le \f(CW\*(C`motif\-non\*(C'\fR qui doit e\*^tre reconnu. .PP La \f(CW\*(C`condition\*(C'\fR a deux formes possibles. La premie\*`re forme est simplement un entier entre parenthe\*`ses \f(CW\*(C`(entier)\*(C'\fR. La condition est vraie si le regroupement me\*'morise\*' correspondant \f(CW\*(C`\eentier\*(C'\fR a e\*'te\*' reconnue plus to\*^t dans l'expression rationnelle. La seconde forme est une assertion de longueur nulle \f(CW\*(C`(?...)\*(C'\fR, soit en avant, soit en arrie\*`re, soit une assertion de code (dont on parlera dans la section suivante). .PP La premie\*`re forme de la \f(CW\*(C`condition\*(C'\fR nous permet de choisir, avec plus de flexibilite\*', ce que l'on veut reconnai\*^tre en fonction de ce qui a de\*'ja\*` e\*'te\*' reconnu. L'exemple suivant cherche les mots de la forme \f(CW"$x$x"\fR ou \&\f(CW"$x$y$y$x"\fR\ : .PP .Vb 9 \& % simple_grep '^(\ew+)(\ew+)?(?(2)\e2\e1|\e1)$' /usr/dict/words \& beriberi \& coco \& couscous \& deed \& ... \& toot \& toto \& tutu .Ve .PP La \f(CW\*(C`condition\*(C'\fR sous la forme d'une assertion de longueur nulle en arrie\*`re, combine\*'e avec des re\*'fe\*'rences arrie\*`res, permet a\*` une partie de la reconnaissance d'influencer une autre partie de la reconnaissance qui arrive plus tard. Par exemple\ : .PP .Vb 1 \& /[ATGC]+(?(?<=AA)G|C)$/; .Ve .PP reconnai\*^t une se\*'quence d'\s-1ADN\s0 qui ne se termine ni par \f(CW\*(C`AAG\*(C'\fR ni par \&\f(CW\*(C`C\*(C'\fR. Remarquez la notation \f(CW\*(C`(?(?<=AA)G|C)\*(C'\fR et non pas \f(CW\*(C`(?((?<=AA))G|C)\*(C'\fR ; pour les assertions de longueur nulle, les parenthe\*`ses ne sont pas ne\*'cessaires. .Sh "Un peu de magie\ : exe\*'cution de code Perl dans une expression rationnelle" .IX Subsection "Un peu de magie: exe'cution de code Perl dans une expression rationnelle" Normalement les expressions rationnelles sont une partie d'une expression Perl. Les expressions d'\fBe\*'valuation\ de\ code\fR\ renversent cela en permettant de placer n'importe quel code Perl a\*` l'inte\*'rieur d'une expression rationnelle. Une expression d'e\*'valuation de code est note\*'e \f(CW\*(C`(?{code})\*(C'\fR ou\*` \f(CW\*(C`code\*(C'\fR est une chai\*^ne contenant des instructions Perl. .PP Une expression d'e\*'valuation de code est une assertion de longueur nulle et la valeur qu'elle retourne de\*'pend de son environnement. Il y a deux possibilite\*'s : soit l'expression est utilise\*'e comme condition dans une expression conditionnelle \f(CW\*(C`(?(condition)...)\*(C'\fR soit ce n'est pas le cas. Si l'expression d'e\*'valuation de code est une condition, le code est e\*'value\*' et son re\*'sultat (c'est a\*` dire le re\*'sultat de la dernie\*`re instruction) est utilise\*' pour de\*'terminer la ve\*'racite\*' de la condition. Si l'expression d'e\*'valuation de code n'est pas une condition, l'assertion est toujours vraie et le re\*'sultat du code est stocke\*' dans la variable spe\*'ciale \f(CW$^R\fR. Cette variable peut e\*^tre utilise\*'e dans des expressions d'e\*'valuation de code apparaissant plus tard dans l'expression rationnelle. Voici quelques exemples\ : .PP .Vb 5 \& $x = "abcdef"; \& $x =~ /abc(?{print "Hi Mom!";})def/; # reconnue, \& # affiche 'Hi Mom!' \& $x =~ /aaa(?{print "Hi Mom!";})def/; # non reconnue, \& # pas de 'Hi Mom!' .Ve .PP Attention a\*` l'exemple suivant\ : .PP .Vb 3 \& $x =~ /abc(?{print "Hi Mom!";})ddd/; # non reconnue, \& # pas de 'Hi Mom!' \& # mais pourquoi ? .Ve .PP En premie\*`re approximation, vous pourriez croire qu'il n'y a pas d'affichage parce que \f(CW\*(C`ddd\*(C'\fR ne peut e\*^tre reconnue dans la chai\*^ne explore\*'e. Mais regardez l'exemple qui suit\ : .PP .Vb 2 \& $x =~ /abc(?{print "Hi Mom!";})[d]dd/; # non reconnue, \& # mais _affiche_ 'Hi Mom!' .Ve .PP Que s'est\-il passe\*' dans ce cas ? Si vous avez tout suivi jusqu'ici, vous savez que les deux expressions rationnelles pre\*'ce\*'dentes sont e\*'quivalentes \*(-- enfermer le d dans une classe de caracte\*`res ne change en rien ce qui peut e\*^tre reconnu. Alors pourquoi l'une n'affiche rien alors que l'autre le fait ? .PP La re\*'ponse est lie\*'e aux optimisations faites par le moteur d'expressions rationnelles. Dans le premier cas, tout ce que le moteur voit c'est une se\*'rie de caracte\*`res simples (mis a\*` part la construction \&\f(CW\*(C`?{}\*(C'\fR). Il est assez habile pour s'apercevoir que la chai\*^ne 'ddd' n'apparai\*^t pas dans la chai\*^ne explore\*'e avant me\*^me de commencer son exploration. Alors que dans le second cas, nous avons utilise\*' une astuce pour lui faire croire que notre motif e\*'tait plus complique\*' qu'il ne l'est. Il voit donc notre classe de caracte\*`res et de\*'cide qu'il doit commencer l'exploration pour de\*'terminer si notre expression rationnelle peut ou non e\*^tre reconnue. Et lors de cette exploration, il atteint l'instruction d'affichage avant de s'apercevoir qu'il n'y a pas de correspondance possible. .PP Pour en savoir un peu plus sur les optimisations faites par le moteur, reportez-vous a\*` la section \*(L"Directives (pragma) et de\*'verminage\*(R" plus bas. .PP D'autres exemples avec \f(CW\*(C`?{}\*(C'\fR: .PP .Vb 6 \& $x =~ /(?{print "Hi Mom!";})/; # reconnue, \& # affiche 'Hi Mom!' \& $x =~ /(?{$c = 1;})(?{print "$c";})/; # reconnue, \& # affiche '1' \& $x =~ /(?{$c = 1;})(?{print "$^R";})/; # reconnue, \& # affiche '1' .Ve .PP La magie e\*'voque\*'e dans le titre de cette section apparai\*^t lorsque le processus de recherche de correspondance effectue un retour arrie\*`re. Si le retour arrie\*`re implique une expression d'e\*'valuation de code et si les variables modifie\*'es par ce code ont e\*'te\*' localise\*'es (via \&\f(CW\*(C`local\*(C'\fR) alors les modifications faites sur ces variables sont annule\*'es ! Donc, si vous voulez compter le nombre de fois ou un caracte\*`re a\*` e\*'te\*' reconnu lors d'une mise en correspondance, vous pouvez utiliser le code suivant\ : .PP .Vb 11 \& $x = "aaaa"; \& $count = 0; # initialisation du compteur de 'a' \& $c = "bob"; # pour montrer que $c n'est pas modifie\*' \& $x =~ /(?{local $c = 0;}) # initialisation du compteur \& ( a # 'a' est reconnu \& (?{local $c = $c + 1;}) # incre\*'mentation du compteur \& )* # on re\*'pe\*`te cela autant que possible \& aa # mais on reconnai\*^t 'aa' a\*` la fin \& (?{$count = $c;}) # recopie de $c local dans $count \& /x; \& print "'a' count is $count, \e$c variable is '$c'\en"; .Ve .PP Ce code affiche\ : .PP .Vb 1 \& 'a' count is 2, $c variable is 'bob' .Ve .PP Si nous remplac\*,ons \f(CW\*(C`\ (?{local\ $c\ =\ $c\ +\ 1;})\*(C'\fR\ par \f(CW\*(C`\ (?{$c\ =\ $c\ +\ 1;})\*(C'\fR\ , les modifications faites a\*` la variable ne sont \fIpas\fR annule\*'es lors du retour arrie\*`re et nous obtenons\ : .PP .Vb 1 \& 'a' count is 4, $c variable is 'bob' .Ve .PP Notez bien que seules les modifications aux variables localise\*'es sont annule\*'es. Les autres effets secondaires de l'exe\*'cution du code sont permanents. Donc\ : .PP .Vb 2 \& $x = "aaaa"; \& $x =~ /(a(?{print "Yow\en";}))*aa/; .Ve .PP produit\ : .PP .Vb 4 \& Yow \& Yow \& Yow \& Yow .Ve .PP Le re\*'sultat \f(CW$^R\fR est automatiquement localise\*'s et donc il se comporte bien lors de retours arrie\*`re. .PP Cet exemple utilise une expression d'e\*'valuation de code dans une condition pour reconnai\*^tre l'article 'the' soit en anglais soit en allemand\ : .PP .Vb 11 \& $lang = 'DE'; # en allemand \& ... \& $text = "das"; \& print "matched\en" \& if $text =~ /(?(?{ \& $lang eq 'EN'; # est\-on en anglais ? \& }) \& the | # si oui, alors il faut reconnai\*^tre 'the' \& (die|das|der) # sinon, reconnai\*^tre 'die|das|der' \& ) \& /xi; .Ve .PP Remarquez ici que la syntaxe est \f(CW\*(C`(?(?{...})motif\-oui|motif\-non)\*(C'\fR et non pas \f(CW\*(C`(?((?{...}))motif\-oui|motif\-non)\*(C'\fR. En d'autres termes, dans le cas d'une expression d'e\*'valuation de code, les parenthe\*`ses autour de la condition sont optionnelles. .PP Si vous tentez d'utiliser des expressions d'e\*'valuation de code combine\*'es avec des variables interpole\*'es, perl risque de vous surprendre\ : .PP .Vb 5 \& $bar = 5; \& $pat = '(?{ 1 })'; \& /foo(?{ $bar })bar/; # se compile bien, $bar n'est pas interpole\*'e \& /foo(?{ 1 })$bar/; # erreur de compilation ! \& /foo${pat}bar/; # erreur de compilation ! \& \& $pat = qr/(?{ $foo = 1 })/; # pre\*'compilation d'une expression \& /foo${pat}bar/; # se compile bien .Ve .PP Si une expression rationnelle contient soit des expressions d'e\*'valuation de code et des variables interpole\*'es, soit une variable dont l'interpolation donne une expression d'e\*'valuation de code, perl traite cela comme une erreur dans l'expression rationnelle. En revanche, si l'expression d'e\*'valuation de code est pre\*'compile\*'e dans une variable, l'interpolation fonctionne. Pourquoi cette erreur ? .PP C'est parce que la combinaison de l'interpolation de variables et des expressions d'e\*'valuation de code est risque\*'e. Elle est risque\*'e parce que beaucoup de programmeurs qui e\*'crivent des moteurs de recherche utilisent directement les valeurs fournies par l'utilisateur dans leurs expressions rationnelles\ : .PP .Vb 3 \& $regexp = <>; # lecture de l'expression rationnelle de l'utilisateur \& $chomp $regexp; # suppression d'un e\*'ventuel passage a\*` la ligne \& $text =~ /$regexp/; # recherche de $regexp dans $text .Ve .PP Si la variable \f(CW$regexp\fR pouvait contenir des expressions d'e\*'valuation de code, l'utilisateur pourrait exe\*'cuter n'importe quel code Perl. Par exemple, un petit rigolo pourrait chercher \&\f(CW\*(C`system('rm\ \-rf\ *');\*(C'\fR\ pour effacer tous vos fichiers. En ce sens, la combinaison de l'interpolation de variables et des expressions d'e\*'valuation de code \fBsouillerait\fR votre expression rationnelle. Donc, par de\*'faut, cette combinaison n'est pas autorise\*'e. \s-1SI\s0 vous n'e\*^tes pas concerne\*' par les utilisateurs malicieux, il est possible de de\*'sactiver cette interdiction en invoquant \f(CW\*(C`use\ re\ 'eval'\*(C'\fR\ : .PP .Vb 5 \& use re 'eval'; # pas de se\*'curite\*' \& $bar = 5; \& $pat = '(?{ 1 })'; \& /foo(?{ 1 })$bar/; # se compile bien \& /foo${pat}bar/; # se compile bien .Ve .PP Une autre forme d'expressions impliquant une e\*'valuation de code est l'expression d'e\*'valuation de code produisant un motif. Cette expression est comme la pre\*'ce\*'dente sauf que le re\*'sultat de l'e\*'valuation du code est traite\*' comme un e\*'le\*'ment d'expression rationnelle a\*` mettre en correspondance imme\*'diatement. Voici un exemple simple\ : .PP .Vb 4 \& $length = 5; \& $char = 'a'; \& $x = 'aaaaabb'; \& $x =~ /(??{$char x $length})/x; # reconnue, il y a bien 5 'a' .Ve .PP Le dernier exemple contient a\*` la fois des expressions ordinaires et des expressions impliquant de l'e\*'valuation de code. Il de\*'tecte si les espacements entre les \f(CW1\fR d'une chai\*^ne binaire \f(CW1101010010001...\fR respectent une suite de Fibonacci 0, 1, 1, 2, 3, 5... .PP .Vb 10 \& $s0 = 0; $s1 = 1; # conditions initiales \& $x = "1101010010001000001"; \& print "It is a Fibonacci sequence\en" \& if $x =~ /^1 # on reconnai\*^t le '1' initial \& ( \& (??{'0' x $s0}) # reconnai\*^t $s0 '0' \& 1 # puis un '1' \& (?{ \& $largest = $s0; # la plus large se\*'quence \& $s2 = $s1 + $s0; # calcule du terme suivant \& $s0 = $s1; # dans la suite de Fibonacci \& $s1 = $s2; \& }) \& )+ # re\*'pe\*'te\*' autant que possible \& $ # c'est la fin \& /x; \& print "Largest sequence matched was $largest\en"; .Ve .PP Cela affiche\ : .PP .Vb 2 \& It is a Fibonacci sequence \& Largest sequence matched was 5 .Ve .PP Remarquez que les variables \f(CW$s0\fR et \f(CW$s1\fR ne sont pas interpole\*'es lorsque l'expression rationnelle est compile\*'e comme cela se passerait pour des variables en dehors d'une expression d'e\*'valuation de code. En fait, le code est e\*'value\*' a\*` chaque fois que perl le rencontre lors de la mise en correspondance. .PP Cette expression rationnelle sans le modificateur \f(CW\*(C`//x\*(C'\fR est\ : .PP .Vb 1 \& /^1((??{'0'x$s0})1(?{$largest=$s0;$s2=$s1+$s0$s0=$s1;$s1=$s2;}))+$/; .Ve .PP et c'est un bon de\*'part pour le concours d'Obfuscated Perl ;\-) Lorsqu'on utilise du code et des expressions conditionnelles, la forme e\*'tendue des expressions rationnelles est toujours ne\*'cessaire pour e\*'crire et de\*'boguer ces expressions. .Sh "Directives (pragma) et de\*'verminage" .IX Subsection "Directives (pragma) et de'verminage" Il existe plusieurs directives (pragma) pour contro\*^ler et de\*'boguer les expressions rationnelles en Perl. Nous avons de\*'ja\*` rencontre\*' une directive dans la section pre\*'ce\*'dente, \f(CW\*(C`use\ re\ 'eval';\*(C'\fR\ , qui autorise la coexistence de variables interpole\*'es et d'expressions d'e\*'valuation de code dans la me\*^me expression rationnelle. Les autres directives sont\ : .PP .Vb 3 \& use re 'taint'; \& $tainted = <>; \& @parts = ($tainted =~ /(\ew+)\es+(\ew+)/; # @parts est maintenant souille\*' .Ve .PP La directive \f(CW\*(C`taint\*(C'\fR rend souille\*'es les sous\-chai\*^nes extraites lors d'une mise en correspondance applique\*'e a\*` une chai\*^ne souille\*'e. Ce n'est pas le cas par de\*'faut puisque les expressions rationnelles sont souvent utilise\*'es pour extraire une information su\*^re d'une chai\*^ne souille\*'e. Utilisez \f(CW\*(C`taint\*(C'\fR lorsque l'extraction ne garantit pas la su\*^rete\*' de l'information extraite. Les deux directives \f(CW\*(C`taint\*(C'\fR et \&\f(CW\*(C`eval\*(C'\fR ont une porte\*'e lexicale limite\*'e au bloc qui les englobe. .PP .Vb 2 \& use re 'debug'; \& /^(.*)$/s; # affichage d'information de debug \& \& use re 'debugcolor'; \& /^(.*)$/s; # affichage d'information de debug en couleur .Ve .PP Les directives globales \f(CW\*(C`debug\*(C'\fR et \f(CW\*(C`debugcolor\*(C'\fR vous permettent d'obtenir des informations de\*'taille\*'es lors de la compilation et de l'exe\*'cution des expressions rationnelles. \f(CW\*(C`debugcolor\*(C'\fR est exactement comme \f(CW\*(C`debug\*(C'\fR sauf que les informations sont affiche\*'es en couleur sur les terminaux qui sont capables d'afficher les se\*'quences termcap de colorisation. Voici quelques exemples de sorties\ : .PP .Vb 10 \& % perl \-e 'use re "debug"; "abc" =~ /a*b+c/;' \& Compiling REx `a*b+c' \& size 9 first at 1 \& 1: STAR(4) \& 2: EXACT (0) \& 4: PLUS(7) \& 5: EXACT (0) \& 7: EXACT (9) \& 9: END(0) \& floating `bc' at 0..2147483647 (checking floating) minlen 2 \& Guessing start of match, REx `a*b+c' against `abc'... \& Found floating substr `bc' at offset 1... \& Guessed: match at offset 0 \& Matching REx `a*b+c' against `abc' \& Setting an EVAL scope, savestack=3 \& 0 <> | 1: STAR \& EXACT can match 1 times out of 32767... \& Setting an EVAL scope, savestack=3 \& 1 | 4: PLUS \& EXACT can match 1 times out of 32767... \& Setting an EVAL scope, savestack=3 \& 2 | 7: EXACT \& 3 <> | 9: END \& Match successful! \& Freeing REx: `a*b+c' .Ve .PP Si vous e\*^tes arrive\*'s aussi loin dans ce tutoriel, vous pouvez probablement comprendre a\*` quoi correspondent les diffe\*'rentes parties de cette sortie. La premie\*`re partie\ : .PP .Vb 8 \& Compiling REx `a*b+c' \& size 9 first at 1 \& 1: STAR(4) \& 2: EXACT (0) \& 4: PLUS(7) \& 5: EXACT (0) \& 7: EXACT (9) \& 9: END(0) .Ve .PP de\*'crit la phase de compilation. \f(CWSTAR(4)\fR signifie qu'il y a un objet e\*'toile\*', dans ce cas 'a', et qu'une fois reconnu, il faut aller en 4, c'est a\*` dire \f(CWPLUS(7)\fR. Les lignes du milieu de\*'crivent des heuristiques et des optimisations applique\*'es avant la mise en correspondance\ : .PP .Vb 4 \& floating `bc' at 0..2147483647 (checking floating) minlen 2 \& Guessing start of match, REx `a*b+c' against `abc'... \& Found floating substr `bc' at offset 1... \& Guessed: match at offset 0 .Ve .PP Puis la mise en correspondance est effectue\*'e et les lignes qui restent de\*'crivent ce processus\ : .PP .Vb 12 \& Matching REx `a*b+c' against `abc' \& Setting an EVAL scope, savestack=3 \& 0 <> | 1: STAR \& EXACT can match 1 times out of 32767... \& Setting an EVAL scope, savestack=3 \& 1 | 4: PLUS \& EXACT can match 1 times out of 32767... \& Setting an EVAL scope, savestack=3 \& 2 | 7: EXACT \& 3 <> | 9: END \& Match successful! \& Freeing REx: `a*b+c' .Ve .PP Chaque pas est de la forme \f(CW\*(C`n\ \ \*(C'\fR\ ou\*` \f(CW\*(C`\*(C'\fR est la partie de la chai\*^ne reconnue et \f(CW\*(C`\*(C'\fR est la partie de la chai\*^ne non encore reconnue. \f(CW\*(C`|\ 1:\ STAR\*(C'\fR\ indique que perl est rendu a\*` la ligne 1 de la phase de compilation vue pre\*'ce\*'demment. Voir \&\*(L"De\*'bogage des expressions rationnelles\*(R" in perldebguts pour de plus amples informations. .PP Une autre me\*'thode pour de\*'boguer les expressions rationnelles consiste a\*` inclure des instructions \f(CW\*(C`print\*(C'\fR dans l'expression rationnelle. .PP .Vb 12 \& "that this" =~ m@(?{print "Start at position ", pos, "\en";}) \& t(?{print "t1\en";}) \& h(?{print "h1\en";}) \& i(?{print "i1\en";}) \& s(?{print "s1\en";}) \& | \& t(?{print "t2\en";}) \& h(?{print "h2\en";}) \& a(?{print "a2\en";}) \& t(?{print "t2\en";}) \& (?{print "Done at position ", pos, "\en";}) \& @x; .Ve .PP qui affiche\ : .PP .Vb 8 \& Start at position 0 \& t1 \& h1 \& t2 \& h2 \& a2 \& t2 \& Done at position 4 .Ve .SH "BUGS" .IX Header "BUGS" Les expressions d'e\*'valuation de code, les expressions conditionnelles et les expressions inde\*'pendantes sont \fBexpe\*'rimentales\fR. Ne les utilisez pas dans du code de production. Pas encore. .SH "VOIR AUSSI" .IX Header "VOIR AUSSI" C'est juste un tutoriel. Pour une documentation comple\*`te sur les expressions rationnelles en Perl, voir perlre. .PP Pour plus d'informations sur l'ope\*'rateur de mise en correspondance \&\f(CW\*(C`m//\*(C'\fR et l'ope\*'rateur de substitution \f(CW\*(C`s///\*(C'\fR, voir \&\*(L"Ope\*'rateurs d'expression rationnelle\*(R" in perlop. Pour plus d'informations sur les ope\*'rations de de\*'coupage via \f(CW\*(C`split\*(C'\fR, voir \&\*(L"split\*(R" in perlfunc. .PP Un tre\*`s bon livre sur l'utilisation des expressions rationnelles, voir le livre \fIMastering Regular Expressions\fR par Jeffrey Friedl (e\*'dite\*' par O'Reilly, \s-1ISBN\s0 1556592\-257\-3) (N.d.t: une traduction franc\*,aise existe.) .SH "AUTEURS ET COPYRIGHT" .IX Header "AUTEURS ET COPYRIGHT" Copyright (c) 2000 Mark Kvale Tous droits re\*'serve\*'s. .PP Ce document peut e\*^tre distribue\*' sous les me\*^mes conditions que Perl lui\-me\*^me. .Sh "Remerciements" .IX Subsection "Remerciements" L'exemple des codons dans une chai\*^ne d'\s-1ADN\s0 est librement inspire\*' de l'exemple de codes \s-1ZIP\s0 du chapitre 7 de \fIMastering Regular Expressions\fR. .PP L'auteur tient a\*` remercier Jeff Pinyan, Andrew Johnson, Peter Haworth, Ronald J Kimball et Joe Smith pour leur aide et leurs commentaires. .SH "TRADUCTION" .IX Header "TRADUCTION" .Sh "Version" .IX Subsection "Version" Cette traduction franc\*,aise correspond a\*` la version anglaise distribue\*'e avec perl 5.8.8. Pour en savoir plus concernant ces traductions, consultez . .Sh "Traducteur" .IX Subsection "Traducteur" Traduction initiale et mise a\*` jour\ : Paul Gaborit \f(CW\*(C`Paul.Gaborit at enstimac.fr\*(C'\fR. .Sh "Relecture" .IX Subsection "Relecture" Jean-Louis Morel