Question

J'ai un fichier journal ASCII avec du contenu que je voudrais extraire. Je n'ai jamais pris le temps d'apprendre correctement Perl, mais je pense que c'est un bon outil pour cette tâche.

Le fichier est structuré comme suit:

... 
... some garbage 
... 
... garbage START
what i want is 
on different
lines 
END 
... 
... more garbage ...
next one START 
more stuff I want, again
spread 
through 
multiple lines 
END 
...
more garbage

Je cherche donc un moyen d'extraire les lignes entre chaque chaîne de délimiteur START et END . Comment puis-je faire cela?

Jusqu'à présent, je n'ai trouvé que quelques exemples sur la façon d'imprimer une ligne avec la chaîne START , ou d'autres éléments de documentation quelque peu liés à ce que je recherche.

Était-ce utile?

La solution

Vous voulez l'opérateur de la bascule (plus connu sous le nom d'opérateur de plage) ..

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

while (<>) {
  if (/START/../END/) {
    next if /START/ || /END/;
    print;
  }
}

Remplacez l'appel à print par ce que vous voulez réellement faire (p. ex., placez la ligne dans un tableau, modifiez-le, formatez-le, etc.). Je passe à côté au-delà des lignes comportant START ou FIN , mais vous ne voudrez peut-être pas ce comportement. Voir cet article pour une discussion de cet opérateur et d'autres variables spéciales Perl utiles.

Autres conseils

De la réponse de perlfaq6 à Comment puis-je tirer des lignes entre deux modèles qui sont eux-mêmes sur des lignes différentes?

Vous pouvez utiliser l'opérateur un peu exotique de Perl (documenté dans perlop):

perl -ne 'print if /START/ .. /END/' file1 file2 ...

Si vous vouliez du texte et non des lignes, vous utiliseriez

perl -0777 -ne 'print "$1\n" while /START(.*?)END/gs' file1 file2 ...

Mais si vous souhaitez que des occurrences imbriquées de START à FIN soient rencontrées, vous vous heurterez au problème décrit dans la question de la correspondance dans cette section sur la correspondance du texte équilibré.

Voici un autre exemple d'utilisation ..:

while (<>) {
    $in_header =   1  .. /^$/;
    $in_body   = /^$/ .. eof;
# now choose between them
} continue {
    $. = 0 if eof;  # fix $.
}

Comment puis-je en saisir plusieurs lignes après une ligne correspondante en Perl?

Comment ça va? Dans celui-ci, la chaîne END est $ ^, vous pouvez le changer pour votre chaîne END.

Je suis aussi un novice, mais les solutions proposées ici fournissent pas mal de méthodes ... faites-moi savoir plus précisément ce que vous voulez qui diffère du lien ci-dessus.

while (<>) {
    chomp;      # strip record separator
    if(/END/) { $f=0;}
    if (/START/) {
        s/.*START//g;
        $f=1;
    }
    print <*>

essayez d'écrire du code la prochaine fois

."\n" if $f; }

essayez d'écrire du code la prochaine fois

Après la réponse de Télémaque, les choses ont commencé à couler. Cela fonctionne comme la solution que je cherche après tout.

  1. J'essaie d'extraire des lignes délimitées par deux chaînes (une avec une ligne se terminant par "CINFILE ="; une autre, avec une ligne contenant un seul "#") dans des lignes séparées, à l'exclusion du délimiteur. lignes. Je peux le faire avec la solution de Télémaque.
  2. La première ligne comporte un espace que je souhaite supprimer. Je l’inclus aussi.
  3. J'essaie également d'extraire chaque ensemble de lignes dans des fichiers séparés.

Cela fonctionne pour moi, bien que le code puisse être classé comme laid; C'est parce que je suis pratiquement un nouvel arrivant sur Perl. Quoi qu'il en soit, voici:

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

my $start='CINFILE=

J'espère que cela profite également aux autres. Cheers.

; my $stop='^#

J'espère que cela profite également aux autres. Cheers.

; my $filename; my $output; my $counter=1; my $found=0; while (<>) { if (/$start/../$stop/) { $filename=sprintf("boletim_%06d.log",$counter); open($output,'>>'.$filename) or die $!; next if /$start/ || /$stop/; if($found == 0) { print $output (split(/ /))[1]; } else { print $output

Après la réponse de Télémaque, les choses ont commencé à couler. Cela fonctionne comme la solution que je cherche après tout.

  1. J'essaie d'extraire des lignes délimitées par deux chaînes (une avec une ligne se terminant par "CINFILE ="; une autre, avec une ligne contenant un seul "#") dans des lignes séparées, à l'exclusion du délimiteur. lignes. Je peux le faire avec la solution de Télémaque.
  2. La première ligne comporte un espace que je souhaite supprimer. Je l’inclus aussi.
  3. J'essaie également d'extraire chaque ensemble de lignes dans des fichiers séparés.

Cela fonctionne pour moi, bien que le code puisse être classé comme laid; C'est parce que je suis pratiquement un nouvel arrivant sur Perl. Quoi qu'il en soit, voici:

<*>

J'espère que cela profite également aux autres. Cheers.

; } $found=1; } else { if($found == 1) { close($output); $counter++; $found=0; } } }

J'espère que cela profite également aux autres. Cheers.

Pas si mal pour venir d'un "nouveau client virtuel". Une chose que vous pouvez faire est de mettre le " $ trouvé = 1 " à l’intérieur du " if ($ found == 0) " bloquer afin que vous ne fassiez pas cette affectation à chaque fois entre $ start et $ stop.

Une autre chose un peu moche, à mon avis, est que vous ouvrez le même gestionnaire de fichiers à chaque fois que vous entrez le bloc $ start / $ stop-block.

Cela montre un moyen de contourner ce problème:

#!/usr/bin/perl

use strict;
use warnings;

my $start='CINFILE=;
my $stop='^#;
my $filename;
my $output;
my $counter=1;
my $found=0;

while (<>) {

    # Find block of lines to extract                                                           
    if( /$start/../$stop/ ) {

        # Start of block                                                                       
        if( /$start/ ) {
            $filename=sprintf("boletim_%06d.log",$counter);
            open($output,'>>'.$filename) or die $!;
        }
        # End of block                                                                         
        elsif ( /$end/ ) {
            close($output);
            $counter++;
            $found = 0;
        }
        # Middle of block                                                                      
        else{
            if($found == 0) {
                print $output (split(/ /))[1];
                $found=1;
            }
            else {
                print $output 

Pas si mal pour venir d'un "nouveau client virtuel". Une chose que vous pouvez faire est de mettre le " $ trouvé = 1 " à l’intérieur du " if ($ found == 0) " bloquer afin que vous ne fassiez pas cette affectation à chaque fois entre $ start et $ stop.

Une autre chose un peu moche, à mon avis, est que vous ouvrez le même gestionnaire de fichiers à chaque fois que vous entrez le bloc $ start / $ stop-block.

Cela montre un moyen de contourner ce problème:

<*>; } } } # Find block of lines to extract }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top