.\" 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 "PERLFAQ6 1" .TH PERLFAQ6 1 "2006-04-08" "DocFr" "User Contributed Perl Documentation" .SH "NAME/NOM" .IX Header "NAME/NOM" perlfaq6 \- Expressions rationnelles ($Revision: 1.38 $, \f(CW$Date:\fR 2005/12/31 00:54:37 $) .SH "DESCRIPTION" .IX Header "DESCRIPTION" Cette partie de la \s-1FAQ\s0 est incroyablement courte car les autres parties sont parseme\*'es de re\*'ponses concernant les expressions rationnelles. Par exemple, de\*'coder une \s-1URL\s0 ou ve\*'rifier si quelque chose est un nombre ou non rele\*`ve du domaine des expressions rationnelles, mais ces re\*'ponses se trouvent ailleurs que dans ce document (dans perlfaq9 X\ Comment de\*'coder ou cre\*'er ces %\-encodings sur le web\ ?\ X et dans perlfaq4 X Comment de\*'terminer si un scalaire est un nombre/entier/a\*` virgule flottante\ ?\ X). .Sh "Comment utiliser les expressions rationnelles sans cre\*'er du code illisible et difficile a\*` maintenir\ ?" .IX Xref "expression rationnelle, lisibilite\*' x regexp, lisibilite\*'" .IX Subsection "Comment utiliser les expressions rationnelles sans cre'er du code illisible et difficile a` maintenir?" Trois me\*'thodes peuvent rendre les expressions rationnelles faciles a\*` maintenir et compre\*'hensibles. .IP "Commentaires en dehors de l'expression rationnelle" 4 .IX Item "Commentaires en dehors de l'expression rationnelle" De\*'crivez ce que vous faites et comment vous le faites en utilisant la fac\*,on habituelle de commenter en Perl. .Sp .Vb 3 \& # transforme la ligne en le premier mot, le signe deux points \& # et le nombre de caracte\*`res du reste de la ligne \& s/^(\ew+)(.*)/ lc($1) . ":" . length($2) /meg; .Ve .IP "Commentaires dans l'expression rationnelle" 4 .IX Item "Commentaires dans l'expression rationnelle" En utilisant le modificateur \f(CW\*(C`/x\*(C'\fR, les espaces seront ignore\*'s dans le motif de l'expression rationnelle (sauf dans une classe de caracte\*`res) et vous pourrez ainsi utiliser les commentaires habituels dedans. Comme vous pouvez l'imaginer, espaces et commentaires aident pas mal. .Sp Un \f(CW\*(C`/x\*(C'\fR vous permet de transformer ceci\ : .Sp .Vb 1 \& s{<(?:[^>'"]*|".*?"|'.*?')+>}{}gs; .Ve .Sp en\ : .Sp .Vb 10 \& s{ < # signe infe\*'rieur \& (?: # parenthe\*`se ouvrante ne cre\*'ant pas de re\*'fe\*'rence \& [^>'"] * # 0 ou plus de caract. qui ne sont ni >, ni ' ni " \& | # ou \& ".*?" # une partie entre guillemets (reconnaissance min) \& | # ou \& '.*?' # une partie entre apostrophes (reconnaissance min) \& ) + # tout cela se produisant une ou plusieurs fois \& > # signe supe\*'rieur \& }{}gsx; # remplace\*' par rien, c.\-a\*`\-d. supprime\*' .Ve .Sp Ce n'est pas encore aussi clair que de la prose, mais c'est tre\*`s utile pour de\*'crire le sens de chaque partie du motif. .IP "Diffe\*'rents de\*'limiteurs" 4 .IX Item "Diffe'rents de'limiteurs" Bien qu'habituellement de\*'limite\*'s par le caracte\*`re \f(CW\*(C`/\*(C'\fR, les motifs peuvent en fait e\*^tre de\*'limite\*'s par quasiment n'importe quel caracte\*`re. perlre l'explique. Par exemple, \f(CW\*(C`s///\*(C'\fR ci-dessus utilise des accolades comme de\*'limiteurs. Se\*'lectionner un autre de\*'limiteur permet d'e\*'viter de le quoter a\*` l'inte\*'rieur du motif\ : .Sp .Vb 2 \& s/\e/usr\e/local/\e/usr\e/share/g; # mauvais choix de de\*'limiteur \& s#/usr/local#/usr/share#g; # meilleur .Ve .Sh "J'ai des proble\*`mes pour faire une reconnaissance sur plusieurs lignes. Qu'est\-ce qui ne va pas\ ?" .IX Xref "expression rationnelle multiligne regexp multiligne" .IX Subsection "J'ai des proble`mes pour faire une reconnaissance sur plusieurs lignes. Qu'est-ce qui ne va pas?" Ou vous n'avez en fait pas plus d'une ligne dans la chai\*^ne ou\*` vous faites la recherche (cas le plus probable), ou vous n'appliquez pas le bon modificateur a\*` votre motif (cas possible). .PP Il y a plusieurs manie\*`res d'avoir plusieurs lignes dans une chai\*^ne. Si vous voulez l'avoir automatiquement en lisant l'entre\*'e, vous initialiserez $/ (probablement a\*` "" pour des paragraphes ou \f(CW\*(C`undef\*(C'\fR pour le fichier entier) ce qui vous permettra de lire plus d'une ligne a\*` la fois. .PP Lire perlre vous aidera a\*` de\*'cider lequel des modificateurs \f(CW\*(C`/s\*(C'\fR ou \&\f(CW\*(C`/m\*(C'\fR (ou les deux) vous utiliserez\ : \f(CW\*(C`/s\*(C'\fR autorise le point a\*` reconnai\*^tre le caracte\*`re fin de ligne alors que \f(CW\*(C`/m\*(C'\fR permet a\*` l'accent circonflexe et au dollar de reconnai\*^tre tous les de\*'buts et fins de ligne, pas seulement le de\*'but et la fin de la chai\*^ne. Vous pouvez utiliser cela pour e\*^tre su\*^r que vous avez bien plusieurs lignes dans votre chaine. .PP Par exemple, ce programme de\*'tecte les mots re\*'pe\*'te\*'s, me\*^me dans des lignes diffe\*'rentes (mais pas dans plusieurs paragraphes). Pour cet exemple, nous n'avons pas besoin de \f(CW\*(C`/s\*(C'\fR car nous n'utilisons pas le point dans l'expression rationnelle qui doit enjamber les fins de ligne. Nous n'avons pas besoin non plus de \f(CW\*(C`/m\*(C'\fR car nous ne voulons pas que le circonflexe ou le dollar fasse une reconnaissance d'un de\*'but ou d'une fin d'une nouvelle ligne. Mais il est impe\*'ratif que $/ ait une autre valeur que la valeur par de\*'faut, ou alors nous n'aurons pas plusieurs lignes d'un coup a\*` se mettre sous la dent. .PP .Vb 8 \& $/ = ''; # lis au moins un paragraphe entier, \& # pas qu'une seule ligne \& while ( <> ) { \& while ( /\eb([\ew'\-]+)(\es+\e1)+\eb/gi ) { # les mots commencent par \& # des caracte\*`res alphanume\*'riques \& print "$1 est re\*'pe\*'te\*' dans le paragraphe $.\en"; \& } \& } .Ve .PP Voila\*` le code qui trouve les phrases commenc\*,ant avec \*(L"From \*(R" (qui devrait e\*^tre transforme\*'s par la plupart des logiciels de courrier e\*'lectronique)\ : .PP .Vb 7 \& $/ = ''; # lis au moins un paragraphe entier, pas qu'une seule ligne \& while ( <> ) { \& while ( /^From /gm ) { # /m fait que ^ reconnaisse \& # tous les de\*'buts de ligne \& print "from de de\*'part dans le paragraphe $.\en"; \& } \& } .Ve .PP Voila\*` le code qui trouve tout ce qu'il y a entre \s-1START\s0 et \s-1END\s0 dans un paragraphe\ : .PP .Vb 7 \& undef $/; # lis le fichier entier, pas seulement qu'une ligne \& # ou un paragraphe \& while ( <> ) { \& while ( /START(.*?)END/sgm ) { # /s fait que . enjambe les lignes \& print "$1\en"; \& } \& } .Ve .Sh "Comment extraire des lignes entre deux motifs qui sont chacun sur des lignes diffe\*'rentes\ ?" .IX Xref ".." .IX Subsection "Comment extraire des lignes entre deux motifs qui sont chacun sur des lignes diffe'rentes?" Vous pouvez utiliser l'ope\*'rateur quelque peu exotique \f(CW\*(C`..\*(C'\fR de Perl (documente\*' dans perlop): .PP .Vb 1 \& perl \-ne 'print if /START/ .. /END/' fichier1 fichier2 ... .Ve .PP Si vous voulez du texte et non des lignes, vous pouvez utiliser .PP .Vb 1 \& perl \-0777 \-ne 'print "$1\en" while /START(.*?)END/gs' fichier1 fichier2 ... .Ve .PP Mais si vous voulez des occurrences imbrique\*'es de \f(CW\*(C`START\*(C'\fR a\*` l'inte\*'rieur de \f(CW\*(C`END\*(C'\fR, vous tombez sur le proble\*`me de\*'crit, dans cette section, sur la reconnaissance de texte bien e\*'quilibre\*'. .PP Ici un autre exemple d'utilisation de \f(CW\*(C`..\*(C'\fR\ : .PP .Vb 7 \& while (<>) { \& $in_header = 1 .. /^$/; \& $in_body = /^$/ .. eof(); \& # maintenant choisissez entre eux \& } continue { \& reset if eof(); # fixe $. \& } .Ve .Sh "J'ai mis une expression rationnelle dans $/ mais cela ne marche pas. Qu'est\-ce qui est faux\ ?" .IX Xref "$ avec expression rationnelle $INPUT_RECORD_SEPARATOR avec expression rationnelle $RS avec expression rationnelle" .IX Subsection "J'ai mis une expression rationnelle dans $/ mais cela ne marche pas. Qu'est-ce qui est faux?" Jusqu'a\*` Perl 5.8 inclus, $/ doit e\*^tre une chai\*^ne. Cela pourrait changer en 5.10 mais n'y compter pas trop tout de me\*^me. En attendant, vous pouvez vous baser sur les exemples ci-dessous si vous en avez re\*'ellement besoin. .PP Si vous disposez de File::Stream, c'est tre\*`s facile. .PP .Vb 5 \& use File::Stream; \& my $stream = File::Stream\->new( \& $filehandle, \& separator => qr/\es*,\es*/, \& ); \& \& print "$_\en" while <$stream>; .Ve .PP Si vous ne disposez pas de File::Stream, il vous faudra en faire un peu plus. .PP Vous pouvez utiliser la forme a\*` quatre argument de sysread pour remplir peu a\*` peu un tampon. Apre\*`s chaque ajout au tampon, vous ve\*'rifiez si vous avez une ligne entie\*`re (en utilisant votre expression rationnelle). .PP .Vb 7 \& local $_ = ""; \& while( sysread FH, $_, 8192, length ) { \& while( s/^((?s).*?)your_pattern/ ) { \& my $record = $1; \& # votre traitement ici. \& } \& } .Ve .PP Vous pouvez faire la me\*^me chose avec un foreach testant une expression rationnelle utilisant le modificateur c et l'ancre \eG si le risque d'avoir tout votre fichier en me\*'moire a\*` la fin ne vous de\*'range pas. .PP .Vb 7 \& local $_ = ""; \& while( sysread FH, $_, 8192, length ) { \& foreach my $record ( m/\eG((?s).*?)your_pattern/gc ) { \& # votre traitement ici. \& } \& substr( $_, 0, pos ) = "" if pos; \& } .Ve .Sh "Comment faire une substitution inde\*'pendante de la casse de la partie gauche mais pre\*'servant cette casse dans la partie droite\ ?" .IX Xref "substitution pre\*'servant la casse remplacement pre\*'servant la casse s pre\*'servant la casse" .IX Subsection "Comment faire une substitution inde'pendante de la casse de la partie gauche mais pre'servant cette casse dans la partie droite?" Voici une adorable solution perlienne par Larry Rosler. Elle exploite les proprie\*'te\*'s du xor bit a\*` bit sur les chai\*^nes \s-1ASCII\s0. .PP .Vb 1 \& $_= "this is a TEsT case"; \& \& $old = 'test'; \& $new = 'success'; \& \& s{(\eQ$old\eE)} \& { uc $new | (uc $1 ^ $1) . \& (uc(substr $1, \-1) ^ substr $1, \-1) x \& (length($new) \- length $1) \& }egi; \& \& print; .Ve .PP Et la voici sous la forme d'un sous\-programme, selon le mode\*`le ci-dessus\ : .PP .Vb 3 \& sub preserve_case($$) { \& my ($old, $new) = @_; \& my $mask = uc $old ^ $old; \& \& uc $new | $mask . \& substr($mask, \-1) x (length($new) \- length($old)) \& } \& \& $a = "this is a TEsT case"; \& $a =~ s/(test)/preserve_case($1, "success")/egi; \& print "$a\en"; .Ve .PP Ceci affiche\ : .PP .Vb 1 \& this is a SUcCESS case .Ve .PP Jeff Pinyan propose une autre manie\*`re de faire qui pre\*'serve la casse du mot de remplacement s'il s'ave\*`re plus long que l'original\ : .PP .Vb 3 \& sub preserve_case { \& my ($from, $to) = @_; \& my ($lf, $lt) = map length, @_; \& \& if ($lt < $lf) { $from = substr $from, 0, $lt } \& else { $from .= substr $to, $lf } \& \& return uc $to | ($from ^ uc $from); \& } .Ve .PP Cela transformera la phrase en \*(L"this is a SUcCess case.\*(R" .PP Rien que pour montrer que les programmeurs C peuvent e\*'crire du C dans tous les langages de programmation, si vous pre\*'fe\*'rez une solution plus proche du style de C, le script suivant fait en sorte que la substitution a la me\*^me casse, lettre par lettre, que l'original (il s'ave\*`re aussi tourner environ 240\ % plus lentement que la version perlienne). Si la substitution a plus de caracte\*`res que la chai\*^ne substitue\*'e, la casse du dernier caracte\*`re est utilise\*'e pour le reste de la substitution. .PP .Vb 8 \& # L'original est de Nathan Torkington, mis en forme par Jeffrey Friedl \& # \& sub preserve_case($$) \& { \& my ($old, $new) = @_; \& my ($state) = 0; # 0 = no change; 1 = lc; 2 = uc \& my ($i, $oldlen, $newlen, $c) = (0, length($old), length($new)); \& my ($len) = $oldlen < $newlen ? $oldlen : $newlen; \& \& for ($i = 0; $i < $len; $i++) { \& if ($c = substr($old, $i, 1), $c =~ /[\eW\ed_]/) { \& $state = 0; \& } elsif (lc $c eq $c) { \& substr($new, $i, 1) = lc(substr($new, $i, 1)); \& $state = 1; \& } else { \& substr($new, $i, 1) = uc(substr($new, $i, 1)); \& $state = 2; \& } \& } \& # on se retrouve avec ce qui reste de new \& # (quand new est plus grand que old) \& if ($newlen > $oldlen) { \& if ($state == 1) { \& substr($new, $oldlen) = lc(substr($new, $oldlen)); \& } elsif ($state == 2) { \& substr($new, $oldlen) = uc(substr($new, $oldlen)); \& } \& } \& return $new; \& } .Ve .ie n .Sh "Comment faire pour que ""\ew"" reconnaisse les caracte\*`res nationaux\ ?" .el .Sh "Comment faire pour que \f(CW\ew\fP reconnaisse les caracte\*`res nationaux\ ?" .IX Xref "\ew" .IX Subsection "Comment faire pour que w reconnaisse les caracte`res nationaux?" Placez \f(CW\*(C`use locale;\*(C'\fR dans votre script. La classe de caracte\*`res \ew est de\*'finie a\*` partir du locale courant. .PP Voir perllocale pour les de\*'tails. .ie n .Sh "Comment reconnai\*^tre une version locale\-e\*'quivalente de ""/[a\-zA\-Z]/""\ ?" .el .Sh "Comment reconnai\*^tre une version locale\-e\*'quivalente de \f(CW/[a\-zA\-Z]/\fP\ ?" .IX Xref "alpha" .IX Subsection "Comment reconnai^tre une version locale-e'quivalente de /[a-zA-Z]/?" Vous pouvez utiliser la classe de caracte\*`res \s-1POSIX\s0 \f(CW\*(C`/[[:alpha:]]/\*(C'\fR qui est documente\*'e dans perlre. .PP Quel que soit le locale courant, les caracte\*`res alphabe\*'tiques sont tous les caracte\*`res reconnus par \ew sauf les chiffres et le caracte\*`re de soulignement. Exprime\*' sous la forme d'une expression rationnelle c\*,a ressemble a\*` \f(CW\*(C`/[^\eW\ed_]/\*(C'\fR. Son comple\*'mentaire, les caracte\*`res non\-alphabe\*'tiques, est tout \eW plus les chiffres et le caracte\*`re de soulignement, donc \f(CW\*(C`/[\eW\ed_]/\*(C'\fR. .Sh "Comment prote\*'ger une variable pour l'utiliser dans une expression rationnelle\ ?" .IX Xref "e\*'chappement dans une expression rationnelle" .IX Subsection "Comment prote'ger une variable pour l'utiliser dans une expression rationnelle?" L'analyseur syntaxique de Perl remplacera par leur valeur les occurences de \f(CW$variable\fR et \f(CW@variable\fR dans les expressions rationnelles a\*` moins que le de\*'limiteur ne soit une apostrophe. Rappelez-vous aussi que la partie droite d'une \f(CW\*(C`s///\*(C'\fR substitution est conside\*'re\*'e comme une chai\*^ne entre guillemets (voir perlop pour plus de de\*'tails). Rappelez-vous encore que n'importe quel caracte\*`re spe\*'cial d'expression rationnelle agira a\*` moins que vous ne pre\*'ce\*'diez la substitution avec \eQ. Voici un exemple\ : .PP .Vb 2 \& $chaine = "Placido P. Octopus"; \& $regex = "P."; \& \& $chaine =~ s/$regex/Polyp/; \& # $chaine est maintenant "Polypacido P. Octopus" .Ve .PP Dans les expressions rationnelles, le \f(CW\*(C`.\*(C'\fR est un caracte\*`re spe\*'cial qui reconnait n'importe quel caracte\*`re, et donc l'expression rationnelle \f(CW\*(C`P.\*(C'\fR reconnait le \f(CW\*(C`Pl\*(C'\fR du de\*'but la chai\*^ne originale. .PP Pour e\*'chapper a\*` la signification spe\*'ciale du \f(CW\*(C`.\*(C'\fR, nous utilisons \&\f(CW\*(C`\eQ\*(C'\fR\ : .PP .Vb 2 \& $chaine = "Placido P. Octopus"; \& $regex = "P."; \& \& $chaine =~ s/\eQ$regex/Polyp/; \& # $chaine est maintenant "Placido Polyp Octopus" .Ve .PP L'utilisation de \f(CW\*(C`\eQ\*(C'\fR fait que le \f(CW\*(C`.\*(C'\fR de l'expression rationnelle est traite\*' comme un caracte\*`re normal, et donc \f(CW\*(C`P.\*(C'\fR reconnait maintenant un \f(CW\*(C`P\*(C'\fR suivi d'un point. .ie n .Sh "A\*` quoi sert vraiment ""/o""\ ?" .el .Sh "A\*` quoi sert vraiment \f(CW/o\fP\ ?" .IX Xref " o" .IX Subsection "A` quoi sert vraiment /o?" L'utilisation d'une variable dans une ope\*'ration de reconnaissance d'expression rationnelle force une re\*'e\*'valuation (et peut\-e\*^tre une recompilation) de l'expression rationnelle a\*` chaque fois qu'elle est applique\*'e. Le modificateur \f(CW\*(C`/o\*(C'\fR verrouille l'expression rationnelle la premie\*`re fois qu'elle est utilise\*'e. C'est toujours ce qui se passe avec une expression rationnelle constante, et en fait, le motif est compile\*' dans le format interne en me\*^me temps que le programme entier l'est. .PP Utiliser \f(CW\*(C`/o\*(C'\fR est peu pertinent a\*` moins que le remplacement de variable ne soit utilise\*' dans le motif, et si cela est, le moteur d'expression rationnelle ne prendra pas en compte les modifications de la variable ulte\*'rieures a\*` la \fItoute premie\*`re\fR e\*'valuation. .PP \&\f(CW\*(C`/o\*(C'\fR est souvent utilise\*' pour gagner en efficacite\*' en ne faisant pas les e\*'valuations ne\*'cessaires quand vous savez que cela ne pose pas de proble\*`me (car vous savez que les variables ne changeront pas), ou plus rarement, quand vous ne voulez pas que l'expression rationnelle remarque qu'elles changent. .PP Par exemple, voici un programme \*(L"paragrep\*(R"\ : .PP .Vb 5 \& $/ = ''; # mode paragraphe \& $pat = shift; \& while (<>) { \& print if /$pat/o; \& } .Ve .Sh "Comment utiliser une expression rationnelle pour enlever les commentaires de type C d'un fichier\ ?" .IX Subsection "Comment utiliser une expression rationnelle pour enlever les commentaires de type C d'un fichier?" Bien que cela puisse se faire, c'est plus complique\*' que vous ne pensez. Par exemple, cette simple ligne .PP .Vb 1 \& perl \-0777 \-pe 's{/\e*.*?\e*/}{}gs' foo.c .Ve .PP marchera dans beaucoup de cas mais pas tous. Vous voyez, c'est un peu simplet pour certains types de programmes C, en particulier, ceux ou\*` des chaines prote\*'ge\*'es sont des commentaires. Pour cela, vous avez besoin de quelque chose de ce genre, cre\*'e\*' par Jeffrey Friedl, modifie\*' ulte\*'rieurement par Fred Curtis\ : .PP .Vb 4 \& $/ = undef; \& $_ = <>; \& s#/\e*[^*]*\e*+([^/*][^*]*\e*+)*/|("(\e\e.|[^"\e\e])*"|'(\e\e.|[^'\e\e])*'|.[^/"'\e\e]*)#defined $2 ? $2 : ""#gse; \& print; .Ve .PP Cela pourrait, e\*'videmment, e\*^tre e\*'crit plus lisiblement avec le modificateur \f(CW\*(C`/x\*(C'\fR en ajoutant des espaces et des commentaires. Le voici e\*'tendu, une gentillesse de Fred Curtis. .PP .Vb 8 \& s{ \& /\e* ## De\*'but d'un commentaire /* ... */ \& [^*]*\e*+ ## Non\-* suivie par 1 ou plusieurs * \& ( \& [^/*][^*]*\e*+ \& )* ## 0 ou plusieurs choses ne commenc\*,ant pas par / \& ## mais finissent par '*' \& / ## Fin d'un commentaire /* ... */ \& \& | ## OU diverses choses qui ne sont pas des commentaires \& \& ( \& " ## De\*'but d'une chai\*^ne " ... " \& ( \& \e\e. ## Caracte\*`re e\*'chappe\*' \& | ## OU \& [^"\e\e] ## Non "\e \& )* \& " ## Fin d'une chai\*^ne " ... " \& \& | ## OU \& \& ' ## De\*'but d'une chai\*^ne ' ... ' \& ( \& \e\e. ## Caracte\*`re e\*'chappe\*' \& | ## OU \& [^'\e\e] ## Non '\e \& )* \& ' ## Fin d'une chai\*^ne ' ... ' \& \& | ## OU \& \& . ## Tout autre caracte\*`re \& [^/"'\e\e]* ## Caracte\*`res ne de\*'butant pas un commentaire, \& ## une chai\*^ne ou un e\*'chappement \& ) \& }{defined $2 ? $2 : ""}gxse; .Ve .PP Une le\*'ge\*`re modification retire aussi les commentaires \*(C+\ : .PP .Vb 1 \& s#/\e*[^*]*\e*+([^/*][^*]*\e*+)*/|//[^\en]*|("(\e\e.|[^"\e\e])*"|'(\e\e.|[^'\e\e])*'|.[^/"'\e\e]*)#defined $2 ? $2 : ""#gse; .Ve .Sh "Est-ce possible d'utiliser les expressions rationnelles de Perl pour reconnai\*^tre du texte bien e\*'quilibre\*'\ ?" .IX Xref "expression rationnelle, texte e\*'quilibre\*' regexp, texte e\*'quilibre\*'" .IX Subsection "Est-ce possible d'utiliser les expressions rationnelles de Perl pour reconnai^tre du texte bien e'quilibre'?" Auparavant, les expressions rationnelles de Perl ne pouvaient pas reconnai\*^tre du texte bien e\*'quilibre\*'. Dans les versions re\*'centes de perl depuis la 5.6.1, des fonctionnalite\*'s expe\*'rimentales ont e\*'te\*' ajoute\*'es afin de rendre possible ces reconnaissances. La documentation de la construction (??{ }) dans perlre montre des exemples de reconnaissances de parenthe\*`ses bien e\*'quilibre\*'es. Assurez-vous de prendre en compte les avertissements pre\*'sents dans cette documentation avant d'utiliser ces fonctionnalite\*'s. .PP Le \s-1CPAN\s0 propose de nombreux modules utiles pour reconnaitre des textes de\*'pendant de leur contexte. Damian Conway fournit quelques expressions pratiques dans Regexp::Common. Le module Text::Balanced fournit une solution ge\*'ne\*'rale a\*` ce proble\*`me. .PP \&\s-1XML\s0 et \s-1HTML\s0 font parties des usages courants de la reconnaissance de textes e\*'quilibre\*'s. Il existe plusieurs modules qui re\*'pondent a\*` ce besoin. Parmi eux HTML::Parser et XML::Parser mais il y en a bien d'autres. .PP Une sous-routine e\*'labore\*'e (pour du 7\-bit \s-1ASCII\s0 seulement) pour extraire de simples caracte\*`res se correspondant et peut\-e\*^tre imbrique\*'s, comme \f(CW\*(C``\*(C'\fR et \f(CW\*(C`'\*(C'\fR, \f(CW\*(C`{\*(C'\fR et \f(CW\*(C`}\*(C'\fR, ou \f(CW\*(C`(\*(C'\fR et \f(CW\*(C`)\*(C'\fR peut e\*^tre trouve\*'e sur . .PP Le module C::Scan du \s-1CPAN\s0 contient de tels sous-programmes pour son usage interne, mais elles ne sont pas documente\*'es. .ie n .Sh "Que veut dire ""les expressions rationnelles sont gourmandes""\ ? Comment puis-je le contourner\ ?" .el .Sh "Que veut dire ``les expressions rationnelles sont gourmandes''\ ? Comment puis-je le contourner\ ?" .IX Xref "gourmand gourmandise" .IX Subsection "Que veut dire les expressions rationnelles sont gourmandes? Comment puis-je le contourner?" La plupart des gens pensent que les expressions rationnelles gourmandes reconnaissent autant qu'elles peuvent. Techniquement parlant, c'est en re\*'alite\*' les quantificateurs (\f(CW\*(C`?\*(C'\fR, \f(CW\*(C`*\*(C'\fR, \f(CW\*(C`+\*(C'\fR, \f(CW\*(C`{}\*(C'\fR) qui sont gourmands pluto\*^t que le motif entier\ ; Perl pre\*'fe\*`re les gourmandises locales et les gratifications imme\*'diates a\*` une gloutonnerie globale. Pour avoir les versions non gourmandes des me\*^mes quantificateurs, utilisez (\f(CW\*(C`??\*(C'\fR, \f(CW\*(C`*?\*(C'\fR, \f(CW\*(C`+?\*(C'\fR, \f(CW\*(C`{}?\*(C'\fR). .PP Un exemple: .PP .Vb 3 \& $s1 = $s2 = "J'ai tre\*`s tre\*`s froid"; \& $s1 =~ s/tr.*s //; # J'ai froid \& $s2 =~ s/tr.*?s //; # J'ai tre\*`s froid .Ve .PP Notez que la seconde substitution arre\*^te la reconnaissance de\*`s qu'un \&\*(L"s \*(R" est rencontre\*'. Le quantificateur \f(CW\*(C`*?\*(C'\fR dit effectivement au moteur des expressions rationnelles de trouver une reconnaissance aussi vite que possible et de passer le contro\*^le a\*` la suite, comme de se refiler une patate chaude. .Sh "Comment examiner chaque mot dans chaque ligne\ ?" .IX Xref "mot" .IX Subsection "Comment examiner chaque mot dans chaque ligne?" Utilisez la fonction split\ : .PP .Vb 5 \& while (<>) { \& foreach $word ( split ) { \& # faire quelque chose avec $word ici \& } \& } .Ve .PP Notez que ce ne sont pas vraiment des mots dans le sens mots franc\*,ais\ ; ce sont juste des suites de caracte\*`res diffe\*'rents des caracte\*`res d'espacement. .PP Pour travailler seulement avec des se\*'quences alphanume\*'riques (caracte\*`re de soulignement inclu), vous pourriez envisager .PP .Vb 5 \& while (<>) { \& foreach $word (m/(\ew+)/g) { \& # faire quelque chose avec $word ici \& } \& } .Ve .Sh "Comment afficher un rapport sur les fre\*'quences de mots ou de lignes\ ?" .IX Subsection "Comment afficher un rapport sur les fre'quences de mots ou de lignes?" Pour faire cela, vous avez a\*` sortir chaque mot du flux d'entre\*'e. Nous appelerons mot une suite de caracte\*`res alphabe\*'tiques, de tirets et d'apostrophes pluto\*^t qu'une suite de tout caracte\*`re sauf espace comme vue dans la question pre\*'ce\*'dente\ : .PP .Vb 8 \& while (<>) { \& while ( /(\eb[^\eW_\ed][\ew'\-]+\eb)/g ) { # on rate "`mouton'" \& $seen{$1}++; \& } \& } \& while ( ($word, $count) = each %seen ) { \& print "$count $word\en"; \& } .Ve .PP Si vous voulez faire la me\*^me chose avec les lignes, vous n'avez pas besoin d'une expression rationnelle\ : .PP .Vb 6 \& while (<>) { \& $seen{$_}++; \& } \& while ( ($line, $count) = each %seen ) { \& print "$count $line"; \& } .Ve .PP Si vous voulez que le re\*'sultat soit trie\*', regardez dans perlfaq4\ : X\ Comment trier une table de hachage (par valeur ou par clef)\ ?\ X. .Sh "Comment faire une reconnaissance approximative\ ?" .IX Xref "reconnaissance approximative" .IX Subsection "Comment faire une reconnaissance approximative?" Regardez le module String::Approx disponible sur \s-1CPAN\s0. .Sh "Comment reconnai\*^tre efficacement plusieurs expressions rationnelles en me\*^me temps\ ?" .IX Xref "expression rationnelle efficace regexp efficace" .IX Subsection "Comment reconnai^tre efficacement plusieurs expressions rationnelles en me^me temps?" (contribution de brian d foy) .PP Ne demandez pas a\*` Perl de recompiler une expression rationnelle a\*` chaque utilisation. Dans l'exemple suivant, perl doit recompiler l'expression rationnelle a\*` chaque passage dans la boucle \fIforeach()\fR puisqu'il n'a aucun moyen de savoir ce que contient \f(CW$motif\fR. .PP .Vb 1 \& @motifs = qw( foo bar baz ); \& \& LINE: while( <> ) \& { \& foreach $motif ( @motifs ) \& { \& print if /\eb$motif\eb/i; \& next LINE; \& } \& } .Ve .PP L'ope\*'rateur qr// est apparu dans la version 5.005 de perl. Il compile une expression rationnelle sans l'appliquer. Lorsque vous utilisez la version pre\*'compile\*'e de l'expression rationnelle, perl a moins de travail a\*` faire. Dans l'exemple suivant, on introduit un \fImap()\fR pour transformer chaque motif en sa version pre\*'compile\*'. Le reste du script est identique mais plus rapide. .PP .Vb 1 \& @motifs = map { qr/\eb$_\eb/i } qw( foo bar baz ); \& \& LINE: while( <> ) \& { \& foreach $motif ( @motifs ) \& { \& print if /$motif/; \& next LINE; \& } \& } .Ve .PP Dans certains cas, vous pouvez me\*^me reconnai\*^tre plusieurs motifs a\*` l'inte\*'rieur d'une me\*^me expression rationnelle. Faites tout de me\*^me attention aux situations amenant a\*` des retours arrie\*`re. .PP .Vb 1 \& $regex = join '|', qw( foo bar baz ); \& \& LINE: while( <> ) \& { \& print if /\eb(?:$regex)\eb/i; \& } .Ve .PP Pour plus de de\*'tails concernant l'efficacite\*' des expressions rationnelles, lisez X\ Mastering Regular Expressions\ X par Jeffrey Freidl. Il explique le fonctionnement du moteur d'expressions rationnelles et pourquoi certains motifs sont e\*'tonnament inefficaces. Une fois que vous aurez bien compris comment perl utilise les expressions rationnelles, vous pourrez les optimiser finement dans toutes les situations. .ie n .Sh "Pourquoi les recherches de limite de mot avec ""\eb"" ne marchent pas pour moi\ ?" .el .Sh "Pourquoi les recherches de limite de mot avec \f(CW\eb\fP ne marchent pas pour moi\ ?" .IX Subsection "Pourquoi les recherches de limite de mot avec b ne marchent pas pour moi?" (contribution de brian d foy) .PP Assurez-vous de bien comprendre ce que \f(CW\*(C`\eb\*(C'\fR repre\*'sente\ : c'est la frontie\*`re entre un caracte\*`re de mot, \f(CW\*(C`\ew\*(C'\fR, et quelque chose qui n'est pas un caracte\*`re de mot. Ce quelque chose qui n'est pas un caracte\*`re de mot peut e\*^tre un \f(CW\*(C`\eW\*(C'\fR mais aussi le de\*'but ou la fin de la chai\*^ne. .PP Ce n'est pas la frontie\*`re entre une caracte\*`re d'espacement et un caracte\*`re autre et ce n'est pas ce qui se\*'pare les mots d'une phrase. .PP En terme d'expression rationnelle, une frontie\*`re de mot (\eb) est une X\ assertion de longueur nulle\ X, ce qui signifie qu'elle ne repre\*'sente pas un caracte\*`re de la chai\*^ne mais une condition a\*` une position donne\*'e. .PP Dans l'expression rationnelle /\ebPerl\eb/, il doit y avoir une frontie\*`re de mot avant le \*(L"P\*(R" et apre\*`s le \*(L"l\*(R". A\*` partir du moment ou\*` autre chose qu'un caracte\*`re de mot pre\*'ce\*`de le \*(L"P\*(R" et suit le \*(L"l\*(R", le motif est reconnu. Les chai\*^nes suivantes sont reconnues par /\ebPerl\eb/. .PP .Vb 5 \& "Perl" # pas de caracte\*`re de mot avant "P" ou apre\*`s "l" \& "Perl " # idem (l'espace n'est pas un caracte\*`re de mot) \& "'Perl'" # l'apostrophe n'est pas un caracte\*`re de mot \& "Perl's" # pas de caracte\*`re de mot avant "P", \& # un caracte\*`re non\-mot apre\*`s "l" .Ve .PP Les chai\*^nes suivantes ne sons pas reconnues par /\ebPerl\eb/. .PP .Vb 2 \& "Perl_" # _ est un caracte\*`re de mot ! \& "Perler" # pas de caracte\*`re de mot avant "P", mais bien apre\*`s "l" .Ve .PP L'usage de \eb ne se limite pas aux mots. Vous pouvez chercher des caracte\*`res non-mot entoure\*'s de caracte\*`res de mot. Les chai\*^nes suivantes sont reconnues par le motif /\eb'\eb/. .PP .Vb 2 \& "don't" # l'apostrophe est entoure\*'e par "n" et "t" \& "qep'a'" # l'apostrophe esr entoure\*'e par "p" et "a" .Ve .PP La chai\*^ne suivante n'est pas reconnue par /\eb'\eb/. .PP .Vb 1 \& "foo'" # aucun caracte\*`re de mot apre\*`s l'apostrophe .Ve .PP Vous pouvez aussi utiliser le comple\*'mentaire de \eb, \eB, pour spe\*'cifier qu'il ne doit pas y avoir de frontie\*`re de mot. .PP Dans le motif /\eBam\eB/, il doit y avoir un caracte\*`re de mot avant le \&\*(L"a\*(R" et apre\*`s le \*(L"m\*(R". Ces chai\*^nes sont reconnues par /\eBam\eB/. .PP .Vb 2 \& "llama" # "am" est entoure\*' par des caracte\*`res de mot \& "Samuel" # idem .Ve .PP Les chai\*^nes suivantes ne sont pas reconnues par /\eBam\eB/. .PP .Vb 2 \& "Sam" # pas de frontie\*`re de mot avant "a", mais apre\*`s "m" \& "I am Sam" # "am" entoure\*'s par des caracte\*`res non\-mot .Ve .Sh "Pourquoi l'utilisation de $&, $`, or $' ralentit tant mon programme\ ?" .IX Xref "$MATCH $& $POSTMATCH $' $PREMATCH $`" .IX Subsection "Pourquoi l'utilisation de $&, $`, or $' ralentit tant mon programme?" (contribution de Anno Siegel) .PP Une fois que Perl sait que vous avez besoin d'une de ces variables quelque part, il les calcule pour chaque reconnaissance de motif. Cela signifie qu'a\*` chaque reconnaissance de motif, la chai\*^ne entie\*`re est recopie\*'e, une partie dans $`, une autre dans $& et le reste dans $'. Le ralentissement est d'autant plus perceptible que les chai\*^nes sont longues et que les motifs sont reconnus. Donc, e\*'vitez $&, $' et $` si vous le pouvez. Et si vous ne le pouvez pas, une fois que vous les avez utilise\*'es, utilisez-les tant que vous voulez, car vous en avez de\*'ja\*` paye\*' le prix. Souvenez-vous que certains algorithmes les appre\*'cient vraiment. A\*` partir de la version 5.005, la variable $& n'a plus le me\*^me cou\*^t que les deux autres. .PP Depuis Perl 5.6.1, les variables spe\*'ciales @\- et @+ peuvent remplacer fonctionnellement $`, $& et $'. Ces tableaux contiennent des pointeurs vers le de\*'but et la fin de chaque partie reconnue (voir perlvar pour tous les de\*'tails). Ils vous donnent donc bien acce\*`s aux me\*^mes informations mais sans l'inconve\*'nient des recopies de chai\*^nes inutiles. .ie n .Sh "A\*` quoi peut bien servir ""\eG"" dans une expression rationnelle\ ?" .el .Sh "A\*` quoi peut bien servir \f(CW\eG\fP dans une expression rationnelle\ ?" .IX Xref "\eG" .IX Subsection "A` quoi peut bien servir G dans une expression rationnelle?" On peut utiliser l'ancre \f(CW\*(C`\eG\*(C'\fR pour de\*'buter une reconnaissance dans une chai\*^ne la\*` ou\*` la recherche pre\*'ce\*'dente s'est arre\*^te\*'e. Le moteur d'expression rationnelle ne peut pas sauter de caracte\*`re pour trouver la prochaine reconnaissance avec cette ancre. Donc <\eG> est similaire a\*` l'ancre de de\*'but de chai\*^ne, \f(CW\*(C`^\*(C'\fR. L'ancre \f(CW\*(C`\eG\*(C'\fR est habiutellement utilise\*'e en conjonction avec le modificateur \f(CW\*(C`/g\*(C'\fR. Elle utilise la valeur de \fIpos()\fR comme position de de\*'part de la prochaine reconnaissance. Au fur et a\*` mesure que l'ope\*'rateur de reconnaissance fait des reconnaissances, il met a\*` jour \fIpos()\fR avec la position du caracte\*`re suivant la dernie\*`re reconnaissance (ou le premier caracte\*`re de la prochaine reconnaissance selon le point de vue qu'on adopte). Chaque chai\*^ne a sa propre valeur \fIpos()\fR. .PP Supposons que vous vouliez reconnai\*^ne toutes les paires conse\*'cutives de chiffres dans une chai\*^ne telle que \*(L"1122a44\*(R" et vous arre\*^tes de\*`s que vous rencontrez autre chose qu'un chiffre. Vous voulez donc reconnai\*^tre \f(CW11\fR et \f(CW22\fR mais la lettre \f(CW\*(C`a\*(C'\fR apparaissant entre \&\f(CW22\fR et \f(CW44\fR doit vous stopper la\*`. La simple reconnaissance de paires de chiffres passerait au\-dela\*` du \f(CW\*(C`a\*(C'\fR et reconnai\*^trait \f(CW44\fR. .PP .Vb 2 \& $_ = "1122a44"; \& my @paires = m/(\ed\ed)/g; # qw( 11 22 44 ) .Ve .PP Si vous utilisez l'ancre \f(CW\*(C`\eG\*(C'\fR, vous forcez la reconnaissance suivant \&\f(CW22\fR a\*` de\*'buter avec \f(CW\*(C`a\*(C'\fR. L'expression rationnelle ne peut donc e\*^tre reconnue puisqu'elle ne trouve pas un chiffre et donc la prochaine reconnaissance e\*'choue et l'ope\*'rateur de reconnaissance retourne la liste des paires de\*'ja\*` trouve\*'es. .PP .Vb 2 \& $_ = "1122a44"; \& my @paires = m/\eG(\ed\ed)/g; # qw( 11 22 ) .Ve .PP Vous pouvez aussi utiliser l'ancre \f(CW\*(C`\eG\*(C'\fR dans un contexte scalaire. Il faut alors utiliser le modificateur \f(CW\*(C`/g\*(C'\fR. .PP .Vb 5 \& $_ = "1122a44"; \& while( m/\eG(\ed\ed)/g ) \& { \& print "Vu $1\en"; \& } .Ve .PP Apre\*`s un e\*'chec de la reconnaissance sur la lettre \f(CW\*(C`a\*(C'\fR, perl re\*'initialise \fIpos()\fR et la prochaine recherche dans la me\*^me chai\*^ne de\*'butera a\*` nouveau au de\*'but. .PP .Vb 5 \& $_ = "1122a44"; \& while( m/\eG(\ed\ed)/g ) \& { \& print "Vu $1\en"; \& } \& \& print "Vu $1 apre\*`s while" if m/(\ed\ed)/g; # trouve "11" .Ve .PP Vous pouvez de\*'sactiver la re\*'initialisation de \fIpos()\fR lors de l'e\*'chec d'une reconnaissance en utilisant le modificateur \f(CW\*(C`/c\*(C'\fR. La prochaines reconnaissances de\*'buteront toutes la\*` ou\*` s'est termine\*'e la dernie\*`re reconnaissance (la valeur de \fIpos()\fR) me\*^me si une reconnaissance sur la me\*^me chai\*^ne a\*` e\*'chouer entre temps. Dans notre cas, la reconnaissance apre\*`s la boucle \fIwhile()\fR commencera au \f(CW\*(C`a\*(C'\fR (la\*` ou\*` s'est termine\*'e la dernie\*`re reconnaissance) et puisqu'elle n'utiliser aucune ancre, elle pourra sauter le \f(CW\*(C`a\*(C'\fR et trouver \*(L"44\*(R". .PP .Vb 5 \& $_ = "1122a44"; \& while( m/\eG(\ed\ed)/gc ) \& { \& print "Vu $1\en"; \& } \& \& print "Vu $1 apre\*`s while" if m/(\ed\ed)/g; # trouve "44" .Ve .PP Typiquement, on utiliser l'ancre \f(CW\*(C`\eG\*(C'\fR avec le modificateur \f(CW\*(C`/c\*(C'\fR lorsqu'on souhaite pouvoir essayer un autre motif si celui-ci e\*'choue, comme dans analyseur syntaxique. Jeffrey Friedl nous offre cet exemple qui fonctionne a\*` partir de la version 5.004. .PP .Vb 9 \& while (<>) { \& chomp; \& PARSER: { \& m/ \eG( \ed+\eb )/gcx && do { print "nombre: $1\en"; redo; }; \& m/ \eG( \ew+ )/gcx && do { print "mot: $1\en"; redo; }; \& m/ \eG( \es+ )/gcx && do { print "espace: $1\en"; redo; }; \& m/ \eG( [^\ew\ed]+ )/gcx && do { print "autre: $1\en"; redo; }; \& } \& } .Ve .PP Pour chaque ligne, la boucle \s-1PARSER\s0 essaie de reconnai\*^tre une se\*'rie de chiffres suivies d'une limite de mot. Cette reconnaissance doit de\*'buter la\*` ou\*` s'est arre\*^te\*'e la pre\*'ce\*'dente reconnaissance (ou\*` au de\*'but de la chai\*^ne la premie\*`re fois). Puisque \f(CW\*(C`m/ \eG( \ed+\eb )/gcx\*(C'\fR utilise le modificateur , me\*^me si la chai\*^ne n'est pas reconnue par l'expression rationnelle, perl ne re\*'initialise pas \fIpos()\fR et essaie le prochain motif en de\*'marrant a\*` la me\*^me position. .Sh "Les expressions rationnelles de Perl sont-elles \s-1AFD\s0 ou \s-1AFN\s0\ ? Sont-elles conformes a\*` \s-1POSIX\s0\ ?" .IX Xref "DFA NFA POSIX" .IX Subsection "Les expressions rationnelles de Perl sont-elles AFD ou AFN? Sont-elles conformes a` POSIX?" Bien qu'il soit vrai que les expressions rationnelles de Perl ressemblent aux \s-1AFD\s0 (automate fini de\*'termine\*') du programme \fIegrep\fR\|(1), elles sont dans les faits imple\*'mente\*'es comme \s-1AFN\s0 (automate fini inde\*'termine\*') pour permettre le retour en arrie\*`re et la me\*'morisation de sous\-motif. Et elles ne sont pas non plus conformes a\*` \s-1POSIX\s0, car celui-ci garantit le comportement du pire dans tous les cas. (Il semble que certains pre\*'fe\*`rent une garantie de conhe\*'rence, me\*^me quand ce qui est garanti est la lenteur). Lisez le livre \*(L"Mastering Regular Expressions\*(R" (from O'Reilly) par Jeffrey Friedl pour tous les de\*'tails que vous pouvez espe\*'rer connai\*^tre sur ces matie\*`res (la re\*'fe\*'rence comple\*`te est dans perlfaq2). .Sh "Qu'est ce qui ne va pas avec l'utilisation de grep dans un contexte vide\ ?" .IX Xref "grep" .IX Subsection "Qu'est ce qui ne va pas avec l'utilisation de grep dans un contexte vide?" Le proble\*`me c'est que grep construit une liste comme re\*'sultat, quel que soit le contexte. Cela signifie que vous amenez Perl a\*` construire une liste que vous allez jeter juste apre\*`s. Si cette liste est grosse, vous ga\*^chez du temps et de l'espace me\*'moire. Si votre objectif est de parcourir la liste alors utiliser une boucle foreach pour cela. .PP Dans les versions de Perl ante\*'rieures a\*` la version 5.8.1, map souffrait du me\*^me proble\*`me. Mais depuis la version 5.8.1, cela a e\*'te\*' corrige\*' et map tient compte maintenant de son contexte \- dans un contexte vide, aucune liste n'est construite. .Sh "Comment reconnai\*^tre des chai\*^nes avec des caracte\*`res multi-octets\ ?" .IX Xref "expression rationnelle et caracte\*`res multi-octets regexp et caracte\*`res multi-octets" .IX Subsection "Comment reconnai^tre des chai^nes avec des caracte`res multi-octets?" Depuis la version 5.6, Perl ge\*'re les caracte\*`res multi-octets avec une qualite\*' qui s'accroi\*^t de version en version. Perl 5.8 ou plus est recommande\*'. Le support des caracte\*`res multi-octets inclut Unicode et les anciens encodages a\*` travers le module Encode. Voir perluniintro, perlunicode et Encode. .PP Si vous utilisez ude vieilles version de Perl, vous pouvez ge\*'rer l'Unicode via le module \f(CW\*(C`Unicode::String\*(C'\fR et les conversion de caracte\*`res en utilisant les modules \f(CW\*(C`Unicode::Map8\*(C'\fR andet \&\f(CW\*(C`Unicode::Map\*(C'\fR. Si vous utilisez les encodages japonais, vous pouvez essayer jperl 5.005_03. .PP Pour finir, Jeffrey Friedl qui a consacre\*' a\*` ce sujet un article dans le nume\*'ro 5 de The Perl Journal, vous offre les approches suivantes. .PP Supposons que vous ayez un codage de ces myste\*'rieux Martiens ou\*` les paires de lettre majuscules \s-1ASCII\s0 codent une lettre simple martienne (i.e. les 2 octets \*(L"\s-1CV\s0\*(R" donne une simple lettre martienne, ainsi que \&\*(L"\s-1SG\s0\*(R", \*(L"\s-1VS\s0\*(R", \*(L"\s-1XX\s0\*(R", etc.). D'autres octets repre\*'sentent de simples caracte\*`res comme l'\s-1ASCII\s0. .PP Ainsi, la chai\*^ne martienne \*(L"Je suis \s-1CVSGXX\s0!\*(R" utilise 15 octets pour coder les 12 caracte\*`res 'J', 'e', ' ', 's', 'u', 'i', 's', ' ', '\s-1CV\s0', \&'\s-1SG\s0', '\s-1XX\s0', '!'. .PP Maintenant, vous voulez chercher le simple caracte\*`re \f(CW\*(C`/GX/\*(C'\fR. Perl ne connai\*^t rien au martien, donc il trouvera les 2 octets \*(L"\s-1GX\s0\*(R" dans la chai\*^ne \*(L"Je suis \s-1CVSGXX\s0!\*(R", alors que ce caracte\*`re n'y est pas: il semble y e\*^tre car \*(L"\s-1SG\s0\*(R" est a\*` co\*^te\*' de \*(L"\s-1XX\s0\*(R", mais il n'y a pas de re\*'el \&\*(L"\s-1GX\s0\*(R". C'est un grand proble\*`me. .PP Voici quelques manie\*`res, toutes pe\*'nibles, de traiter cela\ : .PP .Vb 3 \& $martian =~ s/([A\-Z][A\-Z])/ $1 /g; # garantit que les octets "martiens" \& # ne sont plus contigu\*:s \& print "GX trouve\*'!\en" if $martian =~ /GX/; .Ve .PP Ou ainsi\ : .PP .Vb 6 \& @chars = $martian =~ m/([A\-Z][A\-Z]|[^A\-Z])/g; \& # c'est conceptuellemnt similaire a\*`: @chars = $text =~ m/(.)/g; \& # \& foreach $char (@chars) { \& print "GX trouve\*'!\en", last if $char eq 'GX'; \& } .Ve .PP Ou encore ainsi\ : .PP .Vb 3 \& while ($martian =~ m/\eG([A\-Z][A\-Z]|.)/gs) { # \eG probablement inutile \& print "GX trouve\*'!\en", last if $1 eq 'GX'; \& } .Ve .PP Voici une autre solution propose\*'e par Benjamin Goldberg et qui utilise une assertion ne\*'gative de longueur nulle pour regarder en arrie\*`re. .PP .Vb 5 \& print "found GX!\en" if $martian =~ m/ \& (?); \& if ($line =~ /$pattern/) { } .Ve .PP Ou, puisque vous n'avez aucune garantie que votre utilisateur a entre\*' une expression rationnelle valide, pie\*'gez une e\*'ventuelle exception de cette fac\*,on\ : .PP .Vb 1 \& if (eval { $line =~ /$pattern/ }) { } .Ve .PP Si vous voulez seulement chercher une chai\*^ne et non pas un motif, alors vous devriez soit utiliser la fonction \fIindex()\fR, qui est faite pour cela, soit, s'il est impossible de vous convaincre de ne pas utiliser une expression rationnelle pour autre chose qu'un motif, assurez-vous au moins d'utiliser \f(CW\*(C`\eQ\*(C'\fR...\f(CW\*(C`\eE\*(C'\fR, documente\*' dans perlre. .PP .Vb 1 \& $pattern = ; \& \& open (FILE, $input) or die "Couldn't open input $input: $!; aborting"; \& while () { \& print if /\eQ$pattern\eE/; \& } \& close FILE; .Ve .SH "AUTEUR ET COPYRIGHT" .IX Header "AUTEUR ET COPYRIGHT" Copyright (c) 1997\-1999 Tom Christiansen, Nathan Torkington et autres auteurs cite\*'s ci\-dessus. Tous droits re\*'serve\*'s. .PP Cette documentation est libre\ ; vous pouvez la redistribuer et/ou la modifier sous les me\*^mes conditions que Perl lui\-me\*^me. .PP Inde\*'pendemment de sa distribution, tous les exemples de code de ce fichier sont ici place\*'s dans le domaine public. Vous e\*^tes autorise\*'s et encourage\*'s a\*` utiliser ce code dans vos programmes que ce soit pour votre plaisir ou pour un profit. Un simple commentaire dans le code pre\*'cisant l'origine serait de bonne courtoisie mais n'est pas indispensable. .SH "TRADUCTION" .IX Header "TRADUCTION" La traduction franc\*,aise est distribue\*'e avec les me\*^me droits que sa version originale (voir ci\-dessus). .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" Marianne Roger . Mise a\*` jour : Roland Trique , Paul Gaborit (paul.gaborit at enstimac.fr). .Sh "Relecture" .IX Subsection "Relecture" Re\*'gis Julie\*' (Regis.Julie@cetelem.fr), Ge\*'rard Delafond.