2010-02-11 3 views
2

C: \ Perl \ bin \ perl.exe

use strict; 
use warnings; 


my $numArgs = $#ARGV + 1; 
print "thanks, you gave me $numArgs command-line arguments.\n"; 



while (my $line = <DATA>) { 
    foreach my $argnum (0 .. $#ARGV) { 
     if ($line =~ /$ARGV[$argnum]/) 
      { 
       print $line; 
      } 
    } 
} 

__DATA__ 
A 
B 
Hello World :-) 
Hello World ! 

quand je suis passé un arg, cela fonctionne bien. Tels que je lance test.pl A ou test.pl B ou ** test.pl Bonjour »et question boucle mixte foreach

quand je suis passé deux args, il travaille quelque temps que

réussie. Quand je exécuter test.pl AB ou test.pl A Bonjour ou ** test.pl B Bonjour »

a échoué: quand je lance test.pl Bonjour tout le monde *

lignes produites et en double de sortie:

D:\learning\perl>t.pl Hello World 
thanks, you gave me 2 command-line arguments. 
Hello World :-) 
Hello World :-) 
Hello World ! 
Hello World ! 

D:\learning\perl> 

Comment résoudre ce problème? Merci d'avoir lu et répondu.

[mise à jour] Je ne souhaite pas imprimer les lignes en double.

Répondre

3

Je ne vois pas le problème, votre script traite le __DATA__ et teste tous les mots d'entrée par rapport à lui: puisque "Bonjour" et "Monde" correspondent deux fois chacun, il imprime 4 lignes. Si vous ne voulez pas écrire plusieurs lignes, ajoutez last; après l'instruction print.

+0

Salut Kemp. oui, comme tu l'as dit. Mais je ne veux pas imprimer des lignes en double. Je vous remercie. –

+3

Ajoutez ensuite 'last;' juste après l'instruction 'print'. –

+0

Cela fonctionne beaucoup. Je vous remercie! –

3

La raison pour laquelle vous obtenez la sortie en double est parce que les expressions régulières $line =~ /Hello/ correspond à la fois les lignes « Bonjour tout le monde » et $line =~ /World/ correspond également à deux lignes « Bonjour tout le monde ». Pour éviter cela, vous devrez ajouter quelque chose dont vous devez vous souvenir quelles sont les lignes de la section __DATA__ qui ont déjà été imprimées afin que vous puissiez les ignorer si elles correspondent à un autre argument.

En outre, un nettoyage stylistique très mineur:

#!C:\Perl\bin\perl.exe 
use strict; 
use warnings; 

my $numArgs = @ARGV; 
print "thanks, you gave me $numArgs command-line arguments.\n"; 

while (my $line = <DATA>) { 
    foreach my $arg (@ARGV) { 
     if ($line =~ /$arg/) 
      { 
       print $line; 
      } 
    } 
} 

__DATA__ 
A 
B 
Hello World :-) 
Hello World ! 
  • avec un tableau dans un contexte scalaire retourne sa taille, de sorte $size = @arr est préféré sur $size = $#arr + 1

  • Si vous n'êtes pas allez utilisez un compteur pour autre chose que l'indexation à travers un tableau (for $i (0..$#arr) { $elem = $arr[$i]; ... }), alors il est plus simple et plus simple de faire simplement une boucle sur le tableau à la place (for $elem (@arr) { ... }).

Votre boucle foreach pourrait également être remplacé par une déclaration grep, mais je vais laisser cela comme un exercice pour le lecteur.

+0

+1 Salut Dave, Merci beaucoup pour votre dissection parfaite. –

+0

Bonjour Dave, j'ai trouvé un bug. Si j'exécute 'test.pl World Hello', (échange * Hello World * vers * World Hello *) La sortie est toujours fausse. :-) –

1

En supposant que vous souhaitez imprimer chaque ligne de DATA une seule fois si un ou plusieurs modèles correspondent, vous pouvez utiliser grep. Notez que l'utilisation de \Q pour citer des métacaractères regex dans les arguments de ligne de commande et l'utilisation du tableau @patterns pour précompiler les modèles.

Lire if grep { $line =~ $_ } @patterns à haute voix: Si $line correspond à un ou plusieurs motifs ;-)

#!/usr/bin/perl 

use strict; use warnings; 

printf "Thanks, you gave me %d command line arguments.\n", scalar @ARGV; 

my @patterns = map { qr/\Q$_/ } @ARGV; 

while (my $line = <DATA>) { 
    print $line if grep { $line =~ $_ } @patterns; 
} 

__DATA__ 
A 
B 
Hello World :-) 
Hello World ! 

Voici quelques commentaires sur votre script pour vous aider à apprendre:

my $numArgs = $#ARGV + 1; 
print "thanks, you gave me $numArgs command-line arguments.\n"; 

La ligne de commande les arguments sont en @ARGV (veuillez lire la documentation). En contexte scalaire, @ARGV évalue le nombre d'éléments dans ce tableau. Par conséquent, vous pouvez simplement utiliser:

printf "Thanks, you gave me %d command line arguments.\n", scalar @ARGV; 

De plus, vous pouvez itérer directement sur les éléments de @ARGV dans votre boucle foreach au lieu d'un accès indexé.

while (my $line = <DATA>) { 
    foreach my $arg (@ARGV) { 
     if ($line =~ /$arg/) { 
      print $line; 
     } 
    } 
} 

Maintenant, ce qui arrive à votre programme si je passe à ( sur la ligne de commande? Ou, même World? Que devrait-il se passer?

+0

Selam Sinan, Teşekkür ederim –

+0

BTW, quand j'ai passé '(' à mon programme ci-dessus, produit et généré une erreur 'Unmatched (en regex; marqué par <- ICI en m/(<- HERE/at D: \ learning \ perl \ t .pl ligne 13, ligne 1. ', sinon World? Fonctionne bien Votre script ci-dessus corrigé ce bug –

+0

@Nano HE Rica ederim ;-) La question principale est, voulez-vous' World? 'Pour correspondre à l'entrée étant donné qu'il n'y a pas de chaîne' World? 'Dans' __DATA__'. Elle correspond puisque 'd?' Signifie que le 'd' est optionnel dans le modèle. interpoler '$ _' dans le' qr' signifie que '?' serait cité et maintenant '?' devrait correspondre littéralement. –