2010-11-08 4 views
1

Je voudrais lire un fichier, par exemple. test.test qui contientPerl readline problème

#test:testdescription\n 
#cmd:binary\n 
#return:0\n 
#stdin:|\n 
echo"toto"\n 
echo"tata"\n 
#stdout:|\n 
toto\n 
tata\n 
#stderr:\n 

je parvenais à prendre qui sont après #test:; #cmd: etc ... mais pour stdin ou stdout, je veux prendre toute la ligne avant la prochaine # à une table @stdin et @stdout.

Je fais une boucle while ($line = <TEST>) afin qu'il regarde chaque ligne. Si je vois un modèle /^#stdin:|/, je veux passer à la ligne suivante et prendre cette valeur à un jusqu'à ce que je vois le prochain #. Comment passer à la ligne suivante dans la boucle while?

Répondre

2

Ce format de fichier peut être facilement manipulé avec une certaine créativité dans le choix de la valeur appropriée pour $/:

use strict; use warnings; 

my %parsed; 

{ 
    local $/ = '#'; 
    while (my $line = <DATA>) { 
     chomp $line; 
     my $content = (split /:/, $line, 2)[1]; 
     next unless defined $content; 
     $content =~ s/\n+\z//; 
     if (my ($chan) = $line =~ /^(std(?:err|in|out))/) { 
      $content =~ s/^\|\n//; 
      $parsed{$chan} = [ split /\n/, $content]; 
     } 
     elsif (my ($var) = $line =~ /^(cmd|return|test)/) { 
      $parsed{ $var } = $content; 
     } 
    } 
} 

use YAML; 
print Dump \%parsed; 

__DATA__ 
#test:testdescription 
#cmd:binary 
#return:0 
#stdin:| 
echo"toto" 
echo"tata" 
#stdout:| 
toto 
tata 
#stderr: 

Sortie:

--- 
cmd: binary 
return: 0 
stderr: [] 
stdin: 
    - echo"toto" 
    - echo"tata" 
stdout: 
    - toto 
    - tata 
test: testdescription
+1

Trixy Hobbitssssses !!! +1 :) – DVK

1

MIS À JOUR DÈS par les colmments de l'utilisateur

Si je comprends bien la question, vous voulez lire une ligne supplémentaire dans une boucle?

Si oui, vous pouvez:

  1. faire juste une autre ligne lue dans la boucle.

    my $another_line = <TEST>; 
    
  2. Gardez un peu d'indicateur d'état et de l'utiliser la prochaine itération de la boucle, et accumuler des lignes entre stdins dans un tampon:

    my $last_line_was_stdin = 0; 
    my @line_buffer =(); 
    while ($line = <TEST>) { 
        if (/^#stdin:|/) { 
         # 
         # Some Code to process all lines acccumulated since last "stdin" 
         # 
         @line_buffer =(); 
         $last_line_was_stdin = 1; 
         next; 
        } 
        push @line_buffer, $line; 
    } 
    

    Cette solution ne peut pas faire 100% de ce que vous avez besoin, mais il définit un modèle que vous devez suivre dans l'implémentation de votre machine d'état: lisez une ligne. Vérifiez votre état actuel (si c'est important). En fonction de l'état actuel et d'un modèle dans la ligne, vérifiez ce que fait la ligne courante (ajoutez au tampon? Changez l'état? Si vous modifiez un état, traitez le tampon en fonction du dernier état?)

Aussi, selon votre commentaire, vous avez un bug dans votre regex - le tuyau (|) signifie "OR" dans regex, donc vous dites "si la ligne commence par #stdin OU correspond à une regex vide" - la dernière partie est toujours vrai, votre regex correspondra à 100% du temps. Vous devez échapper à la "|" via /^#stdin:\|/ ou /^#stdin:[|]/

+0

une chose: quand je mets en while ($ line = ) { if ($ line = ~/^ stdin: | /) { impression "l ine "; } } il imprime toutes les lignes dans le fichier. Normalement, il devrait seulement imprimer #stdin: | droite? – Dung

+0

la deuxième solution ne résout pas le problème parce que je veux toute la ligne après | jusqu'à ce que je rencontre un # – Dung

+0

@viet - donc l'étendre pour lire dans une ligne et ajouter au tableau/accumulation scalaire jusqu'à ce que le prochain stdin est trouvé. De plus, quand stdin est trouvé, au lieu de "next" - en suivant la ligne suivante, commencez par traiter tout le buffer/accumulateur et videz-le. J'ai édité la réponse en conséquence – DVK