2009-08-02 7 views
0

Je stocke les informations capturées par regex dans un tableau. Mais pour une raison quelconque, la première valeur est stockée à 4 éléments du tableau. Toute suggestion sur ce qui va mal et comment stocker la première valeur dans le premier élément de tableau.Pourquoi la première valeur de l'expression capturée est-elle stockée dans le quatrième élément de Perl?

Ce qui suit est le script:

#!/usr/bin/perl 

use strict; 
my @value; 
my $find= qr/^\s+([0-9]+)\s+([A-Z])/; 

open (FILE, "</usr/test")|| die "cant open file"; 
my @body=<FILE>; 

foreach my $line (@body){ 
    chomp $line; 
    push @value, join('', $line =~ /$find/); 
} 
print "$value[0]\n"; #does not print anything 
print "$value[4]\n"; #prints first value i.e 1389E 
exit; 

DONNÉES

1389 E not 
    188 S yes 
    24 D yes 
    456 K not 
    2 Q yes 

Répondre

1

Je pense que vous devriez écrire

print "$value[0]\n"; 
print "$value[4]\n"; 

pour accéder aux éléments d'un tableau.

+0

@ David: J'ai écrit @value [0] par erreur. J'utilise $ value [0] pour imprimer la première valeur du tableau. Et, aucune valeur ne s'imprime pour le premier élément, c'est-à-dire $ value [0] – shubster

4

Votre deuxième ligne a plus d'un espace entre le groupe de nombres et la lettre, donc vous voulez probablement \s+ deux fois plutôt que \s la deuxième fois. À la fin, vous ne saurez pas nécessairement combien d'éléments vous avez dans le tableau @value, alors vous voudrez peut-être mettre l'impression dans une boucle for plutôt que de supposer que vous avez un cinquième élément. (Peut-être savez-vous que vous voulez le premier et le cinquième, cependant?) Suivi: basé sur votre édition, vous avez plus de deux entrées après tout. La version que je donne ci-dessous, en utilisant split et \s+ capture le nombre et la lettre pour toutes les lignes. Je vais ajuster la partie imprimée du script pour vous montrer ce que je veux dire.

Quelques autres:

  • Vous devez toujours activer les avertissements.
  • Il n'y a aucune raison de lire tout le fichier dans un tableau et de le parcourir ligne par ligne. Passer le tableau @body et faire ce que vous devez dans la boucle while.
  • Utilisez la forme plus moderne de open avec des handles de fichiers lexicaux et trois arguments.
  • split semble plus simple ici pour moi, plutôt que d'une expression régulière avec des captures. Puisque vous voulez capturer deux parties spécifiques de la ligne, vous pouvez utiliser split avec une tranche de tableau pour saisir ces deux éléments et les envoyer à join.
  • @value n'est pas un nom de variable particulièrement utile, mais je pense que vous devriez au moins le rendre pluriel. Je pense que c'est une bonne habitude d'entrer dans la mesure où le tableau stocke vos enregistrements pluriels. (.. Ce n'est pas une règle stricte et rapide, mais il me mis sur écoute ici Ce point est assez mineur)

Voilà comment tout cela pourrait ressembler:

#!/usr/bin/env perl 
    use warnings; 
    use strict; 

    my @values; 

    # open my $filehandle, '<', '/usr/test' 
    #  or die "Can't open /usr/test: $!"; 

    while (my $line = <DATA>) { 
     chomp $line; 
     push @values, join('', (split /\s+/, $line)[1..2]); 
    } 

    for my $record (@values) { 
     print $record, "\n"; 
    } 

    __DATA__ 
     1389 E not 
     188 S yes 
     24 D yes 
     456 K not 
     2 Q yes 
+0

Est-ce que "... forme d'ouverture avec des handles de fichier lexicaux et trois arguments" ne doit pas être utilisé dans votre exemple de code? Et une portée à partir de? Ou est-ce que j'ai mal compris quelque chose? –

+0

@Peter: Je ne peux pas vraiment utiliser l'instruction 'open', car je n'ai pas le fichier/usr/test de l'OP sur mon disque (et je ne vais pas le créer pour cet exemple). J'ai donc écrit l'exemple pour lui montrer ce que je voulais dire, mais j'utilise le '__DATA__' intégré pour obtenir les fichiers. Pour ce qui est de "la possibilité de sortir de", dans un scénario aussi court, le problème n'est pas vraiment la portée en soi. Je n'insistais pas sur 'lexical' dans les handles de fichiers lexicaux; c'est juste leur nom. Voir ici pour en savoir plus sur les handles de fichiers bareword: http://www.perlfoundation.org/perl5/index.cgi?bareword_uppercase_filehandles – Telemachus

1

Vous devez utiliser les descripteurs de fichiers lexicales et forme de trois arguments de open ainsi que d'éviter de slurping des fichiers inutilement.

Dans tous les cas, la raison la plus probable de votre problème est un seul caractère absent de votre modèle. Comparez celui ci-dessous avec celui que vous avez ci-dessus.

#!/usr/bin/perl 

use strict; 
use warnings; 

my @value; 
my $find= qr/^\s+([0-9]+)\s+([A-Z])/; 

while (my $line = <DATA>) { 
    last unless $line =~ /\S/; 
    push @value, join '', $line =~ $find; 
} 

use Data::Dumper; 
print Dumper \@value; 

__DATA__ 
    1389 E not 
    188 S yes 
    24 D yes 
    456 K not 
    2 Q yes 
+0

@Sinan: mon mauvais, de ne pas utiliser '\ s +' au lieu de '\ s'. Mais, toujours la première valeur est imprimée sur l'impression du premier élément de tableau. – shubster

+0

@shubster Déterminez ce qui est différent entre le code/données ci-dessus et le code/données que vous ne nous montrez pas. –

0

Avez-vous des lignes d'espacement en tête ou d'autres lignes principales dans vos données qui ne correspondent pas à votre expression rationnelle? Puisque vous poussez inconditionnellement() sur votre tableau de sortie, que votre expression rationnelle corresponde ou non, vous obtiendrez des éléments de tableau vides pour chaque ligne qui ne correspond pas à votre entrée.

Observer:

#!/usr/bin/perl 

use strict; 
use warnings; 

my @lines; 

while (<DATA>) { 
    push @lines , (join('' , /^\s*(\d+)/)); 
} 

foreach (0 .. $#lines) { 
    print "$_ -> $lines[$_]\n"; 
} 


__DATA__ 
FOO 
Bar 
Baz 
    1234 
456 
bargle 

Sortie:

0 -> 
1 -> 
2 -> 
3 -> 1234 
4 -> 456 
5 -> 
Questions connexes