1
votes

Résultat inattendu d'une regex de substitution en Perl

J'ai un script et un fichier.

[evelden@vatasu4435 perl]$ script file
35:42
35:42

Donc, à l'arrière de l'expression régulière, il est dit. *, mais pas au début.

Do,

[evelden@vatasu4435 perl]$ ./script file
06:35
foo 06:35

Apparemment. * à la fin prend autant que possible, ce qui est OK.

Mais ce que je Je ne comprends pas d'où vient «foo» dans la réponse. Telle est ma question.

Si je change l'expression régulière dans: s /.* (\ d \ d: \ d \ d). * / \ 1 / , dus à l'avant également. *, alors la réponse est ce à quoi je m'attendais:

[evelden@vatasu4435 perl]$ cat file
06:35:42,734
foo 06:35:42 bar

[evelden@vatasu4435 perl]$ cat script
#!/usr/bin/perl
while(<>){
    if(s/(\d\d:\d\d).*/\1/){
        print;
    }
}

Maintenant, il est gourmand à l'avant, mais ça va.


2 commentaires

Est-ce que 35:42 est vraiment ce que vous attendez, pas 06:35 ?


Si vous voulez imprimer les heures, vous voulez while (<>) {print "$ 1 \ n" while / (\ d \ d: \ d \ d) / g; }


3 Réponses :


3
votes

Le contenu de la ligne courante est placé dans $ _ . Votre s /// fonctionne sur ce $ _ , en remplaçant le modèle complet par le contenu de $ 1 (ou \ 1 , comme vous l'avez dit). C'est le contenu du premier groupe de capture du modèle. Mais votre modèle n'est pas ancré, il commencera donc à correspondre quelque part dans la chaîne et à remplacer à partir de là. Il fait exactement ce que vous lui avez dit.

Si vous vouliez vous débarrasser de tout ce qui se trouve à l'avant, votre deuxième motif est correct. Si vous souhaitez modifier uniquement les lignes qui commencent par le motif, utilisez une ancre ^ à l'avant.


0 commentaires

2
votes

Seule la partie de la ligne qui correspond à l'expression régulière est remplacée par s /// . Puisque l'expression rationnelle n'est pas ancrée à gauche, elle correspond à la partie de la ligne commençant par l'heure et remplace cette partie. La partie avant la correspondance reste inchangée, donc foo reste dans la ligne.


0 commentaires

1
votes

L'expression régulière originale d'OP ne précise pas où commencer ou terminer la capture.

s / (\ d \ d: \ d \ d). * / \ 1 / - recherchez dans la chaîne \ d {2}: \ d {2} et tout ce qui suit. Remplacez le modèle trouvé ( \ d {2}: \ d {2}. * - chiffres par tout ce qui le suit) par deux chiffres capturés \ d {2}: \ d {2} . Il n'y a rien dans le modèle lié à ce qui est avant \ d {2}: \ d {2} et aucun remplacement appliqué à cette partie - foo n'est pas touché.

OP avait peut-être l'intention d'écrire le code suivant

06:35
06:35

Deux solutions simples au problème

use strict;
use warnings;
use feature 'say';

my $data = do { local $/; <DATA> };
my @time = $data =~ /\b(\d{2}:\d{2})/g;

say for @time;

__DATA__
06:35:42,734
foo 06:35:42 bar

Ou une autre variante

use strict;
use warnings;
use feature 'say';

while(<DATA>) {
    /\b(\d{2}:\d{2})/;
    say $1;
}

__DATA__
06:35:42,734
foo 06:35:42 bar

Ou peut être comme suit

use strict;
use warnings;
use feature 'say';

while(<DATA>) {
    /(\d{2}:\d{2}):/;
    say $1;
}

__DATA__
06:35:42,734
foo 06:35:42 bar

Sortie

use strict;
use warnings;

s/.*?(\d{2}:\d{2}):.*/$1/ && print for <>;


0 commentaires