POD2-FR
view release on metacpan or search on metacpan
FR/perlfaq6.pod view on Meta::CPAN
S<en :>
s{ < # signe inférieur
(?: # parenthèse ouvrante ne créant pas de réfé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 supérieur
}{}gsx; # remplacé par rien, c.-à-d. supprimé
Ce n'est pas encore aussi clair que de la prose, mais c'est très utile
pour décrire le sens de chaque partie du motif.
=item Différents délimiteurs
Bien qu'habituellement délimités par le caractère C</>, les motifs
peuvent en fait être délimités par quasiment n'importe quel
caractère. L<perlre> l'explique. Par exemple, C<s///> ci-dessus
utilise des accolades comme délimiteurs. Sélectionner un autre
délimiteur permet d'éviter de le quoter à l'intérieur du S<motif :>
s/\/usr\/local/\/usr\/share/g; # mauvais choix de délimiteur
s#/usr/local#/usr/share#g; # meilleur
=back
=head2 J'ai des problèmes pour faire une reconnaissance sur plusieurs lignes. Qu'est-ce qui ne va S<pas ?> X<expression rationnelle multiligne> X<regexp multiligne>
Ou vous n'avez en fait pas plus d'une ligne dans la chaîne où vous
faites la recherche (cas le plus probable), ou vous n'appliquez pas le
bon modificateur à votre motif (cas possible).
Il y a plusieurs manières d'avoir plusieurs lignes dans une chaîne. Si
vous voulez l'avoir automatiquement en lisant l'entrée, vous
initialiserez $/ (probablement à "" pour des paragraphes ou C<undef>
pour le fichier entier) ce qui vous permettra de lire plus d'une ligne
à la fois.
Lire L<perlre> vous aidera à décider lequel des modificateurs C</s> ou
C</m> (ou les deux) vous S<utiliserez :> C</s> autorise le point à
reconnaître le caractère fin de ligne alors que C</m> permet à
l'accent circonflexe et au dollar de reconnaître tous les débuts et
fins de ligne, pas seulement le début et la fin de la chaîne. Vous
pouvez utiliser cela pour être sûr que vous avez bien plusieurs lignes
dans votre chaine.
Par exemple, ce programme détecte les mots répétés, même dans des
lignes différentes (mais pas dans plusieurs paragraphes). Pour cet
exemple, nous n'avons pas besoin de C</s> 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 C</m> car nous ne voulons
pas que le circonflexe ou le dollar fasse une reconnaissance d'un
début ou d'une fin d'une nouvelle ligne. Mais il est impératif que $/
ait une autre valeur que la valeur par défaut, ou alors nous n'aurons
pas plusieurs lignes d'un coup à se mettre sous la dent.
$/ = ''; # lis au moins un paragraphe entier,
# pas qu'une seule ligne
while ( <> ) {
while ( /\b([\w'-]+)(\s+\1)+\b/gi ) { # les mots commencent par
# des caractères alphanumériques
print "$1 est répété dans le paragraphe $.\n";
}
}
Voilà le code qui trouve les phrases commençant avec "From " (qui
devrait être transformés par la plupart des logiciels de courrier
électronique)E<nbsp>:
$/ = ''; # lis au moins un paragraphe entier, pas qu'une seule ligne
while ( <> ) {
while ( /^From /gm ) { # /m fait que ^ reconnaisse
# tous les débuts de ligne
print "from de départ dans le paragraphe $.\n";
}
}
Voilà le code qui trouve tout ce qu'il y a entre START et END dans un
S<paragraphe :>
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\n";
}
}
=head2 Comment extraire des lignes entre deux motifs qui sont chacun sur des lignes S<différentes ?> X<..>
Vous pouvez utiliser l'opérateur quelque peu exotique C<..> de Perl
(documenté dans L<perlop>):
perl -ne 'print if /START/ .. /END/' fichier1 fichier2 ...
Si vous voulez du texte et non des lignes, vous pouvez utiliser
perl -0777 -ne 'print "$1\n" while /START(.*?)END/gs' fichier1 fichier2 ...
Mais si vous voulez des occurrences imbriquées de C<START> à
l'intérieur de C<END>, vous tombez sur le problème décrit, dans cette
section, sur la reconnaissance de texte bien équilibré.
Ici un autre exemple d'utilisation de S<C<..> :>
while (<>) {
$in_header = 1 .. /^$/;
$in_body = /^$/ .. eof();
# maintenant choisissez entre eux
} continue {
reset if eof(); # fixe $.
}
=head2 J'ai mis une expression rationnelle dans $/ mais cela ne marche pas. Qu'est-ce qui est S<faux ?> X<$/ avec expression rationnelle> X<$INPUT_RECORD_SEPARATOR avec expression rationnelle> X<$RS avec expression rationnelle>
Jusqu'à Perl 5.8 inclus, $/ doit être une chaîne. Cela pourrait
changer en 5.10 mais n'y compter pas trop tout de même. En attendant,
vous pouvez vous baser sur les exemples ci-dessous si vous en avez
réellement besoin.
Si vous disposez de File::Stream, c'est très facile.
use File::Stream;
my $stream = File::Stream->new(
$filehandle,
separator => qr/\s*,\s*/,
);
print "$_\n" while <$stream>;
FR/perlfaq6.pod view on Meta::CPAN
soulignement, donc C</[\W\d_]/>.
=head2 Comment protéger une variable pour l'utiliser dans une expression S<rationnelle ?> X<échappement dans une expression rationnelle>
L'analyseur syntaxique de Perl remplacera par leur valeur les
occurences de $variable et @variable dans les expressions rationnelles à
moins que le délimiteur ne soit une apostrophe. Rappelez-vous aussi
que la partie droite d'une C<s///> substitution est considérée comme
une chaîne entre guillemets (voir L<perlop> pour plus de
détails). Rappelez-vous encore que n'importe quel caractère spécial
d'expression rationnelle agira à moins que vous ne précédiez la
substitution avec \Q. Voici un S<exemple :>
$chaine = "Placido P. Octopus";
$regex = "P.";
$chaine =~ s/$regex/Polyp/;
# $chaine est maintenant "Polypacido P. Octopus"
Dans les expressions rationnelles, le C<.> est un caractère spécial
qui reconnait n'importe quel caractère, et donc l'expression
rationnelle C<P.> reconnait le C<Pl> du début la chaîne originale.
Pour échapper à la signification spéciale du C<.>, nous utilisons
S<C<\Q> :>
$chaine = "Placido P. Octopus";
$regex = "P.";
$chaine =~ s/\Q$regex/Polyp/;
# $chaine est maintenant "Placido Polyp Octopus"
L'utilisation de C<\Q> fait que le C<.> de l'expression rationnelle
est traité comme un caractère normal, et donc C<P.> reconnait
maintenant un C<P> suivi d'un point.
=head2 À quoi sert vraiment S<C</o> ?> X</o>
L'utilisation d'une variable dans une opération de reconnaissance
d'expression rationnelle force une réévaluation (et peut-être une
recompilation) de l'expression rationnelle à chaque fois qu'elle est
appliquée. Le modificateur C</o> verrouille l'expression rationnelle la
première fois qu'elle est utilisée. C'est toujours ce qui se passe
avec une expression rationnelle constante, et en fait, le motif est
compilé dans le format interne en même temps que le programme entier
l'est.
Utiliser C</o> est peu pertinent à moins que le remplacement de
variable ne soit utilisé dans le motif, et si cela est, le moteur
d'expression rationnelle ne prendra pas en compte les modifications de
la variable ultérieures à la I<toute première> évaluation.
C</o> est souvent utilisé pour gagner en efficacité en ne faisant pas
les évaluations nécessaires quand vous savez que cela ne pose pas de
problè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.
Par exemple, voici un programme S<"paragrep" :>
$/ = ''; # mode paragraphe
$pat = shift;
while (<>) {
print if /$pat/o;
}
=head2 Comment utiliser une expression rationnelle pour enlever les commentaires de type C d'un S<fichier ?>
Bien que cela puisse se faire, c'est plus compliqué que vous ne
pensez. Par exemple, cette simple ligne
perl -0777 -pe 's{/\*.*?\*/}{}gs' foo.c
marchera dans beaucoup de cas mais pas tous. Vous voyez, c'est un peu
simplet pour certains types de programmes C, en particulier, ceux où
des chaines protégées sont des commentaires. Pour cela, vous avez
besoin de quelque chose de ce genre, créé par Jeffrey Friedl, modifié
ultérieurement par Fred S<Curtis :>
$/ = undef;
$_ = <>;
s#/\*[^*]*\*+([^/*][^*]*\*+)*/|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)#defined $2 ? $2 : ""#gse;
print;
Cela pourrait, évidemment, être écrit plus lisiblement avec le
modificateur C</x> en ajoutant des espaces et des commentaires. Le
voici étendu, une gentillesse de Fred Curtis.
s{
/\* ## Début d'un commentaire /* ... */
[^*]*\*+ ## Non-* suivie par 1 ou plusieurs *
(
[^/*][^*]*\*+
)* ## 0 ou plusieurs choses ne commençant pas par /
## mais finissent par '*'
/ ## Fin d'un commentaire /* ... */
| ## OU diverses choses qui ne sont pas des commentaires
(
" ## Début d'une chaîne " ... "
(
\\. ## Caractère échappé
| ## OU
[^"\\] ## Non "\
)*
" ## Fin d'une chaîne " ... "
| ## OU
' ## Début d'une chaîne ' ... '
(
\\. ## Caractère échappé
| ## OU
[^'\\] ## Non '\
)*
' ## Fin d'une chaîne ' ... '
| ## OU
. ## Tout autre caractère
( run in 1.355 second using v1.01-cache-2.11-cpan-54e63673c56 )