Come estraggo le linee tra due delimitatori di linea in Perl?
Domanda
Ho un file di registro ASCII con alcuni contenuti che vorrei estrarre. Non ho mai avuto il tempo di imparare correttamente Perl, ma immagino che questo sia un buon strumento per questo compito.
Il file è strutturato in questo modo:
... ... 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
Quindi, sto cercando un modo per estrarre le linee tra ciascuna stringa delimitatore START
e END
.
Come posso farlo?
Finora ho trovato solo alcuni esempi su come stampare una riga con la stringa START
o altri elementi della documentazione che sono in qualche modo correlati a ciò che sto cercando.
Soluzione
Si desidera l'operatore flip-flop (meglio noto come operatore di intervallo) ..
#!/usr/bin/env perl
use strict;
use warnings;
while (<>) {
if (/START/../END/) {
next if /START/ || /END/;
print;
}
}
Sostituisci la chiamata a print
con qualunque cosa tu voglia realmente fare (ad esempio, spingere la linea in un array, modificarla, formattarla, qualunque cosa). Sto successivo
-stando oltre le righe che in realtà hanno START
o END
, ma potresti non voler quel comportamento. Vedi questo articolo per una discussione di questo operatore e di altri utili variabili speciali Perl.
Altri suggerimenti
Dalla perlfaq6 la risposta di Come posso estrarre linee tra due motivi che si trovano su linee diverse?
Puoi usare l'operatore un po 'esotico di Perl (documentato in perlop):
perl -ne 'print if /START/ .. /END/' file1 file2 ...
Se volessi del testo e non delle righe, dovresti usare
perl -0777 -ne 'print "$1\n" while /START(.*?)END/gs' file1 file2 ...
Ma se desideri occorrenze nidificate di START tramite END, ti imbatterai nel problema descritto nella domanda in questa sezione sulla corrispondenza del testo bilanciato.
Ecco un altro esempio dell'uso di ..:
while (<>) {
$in_header = 1 .. /^$/;
$in_body = /^$/ .. eof;
# now choose between them
} continue {
$. = 0 if eof; # fix $.
}
Come posso ottenere più righe dopo una riga corrispondente in Perl?
Come va? In quello, la stringa END è $ ^, puoi cambiarla nella tua stringa END.
Sono anche un principiante, ma le soluzioni lì forniscono alcuni metodi ... fammi sapere più specificamente ciò che vuoi che differisce dal link sopra.
while (<>) {
chomp; # strip record separator
if(/END/) { $f=0;}
if (/START/) {
s/.*START//g;
$f=1;
}
print <*>
prova a scrivere del codice la prossima volta
."\n" if $f;
}
prova a scrivere del codice la prossima volta
Dopo la risposta di Telemaco, le cose hanno iniziato a riversarsi. Funziona come la soluzione che sto cercando dopo tutto.
- Sto cercando di estrarre le linee delimitate da due stringhe (una, con una linea che termina con " CINFILE = " ;; altro, con una linea contenente un singolo " # ") in righe separate, escluso il delimitatore Linee. Questo posso farlo con la soluzione di Telemaco.
- La prima riga ha uno spazio che voglio rimuovere. Lo sto anche includendo.
- Sto anche cercando di estrarre ogni set di righe in file separati.
Questo funziona per me, anche se il codice può essere classificato come brutto; questo perché al momento sono praticamente un nuovo arrivato in Perl. Comunque qui va:
#!/usr/bin/env perl
use strict;
use warnings;
my $start='CINFILE=
Spero che vada a beneficio anche degli altri.
Cin cin.
;
my $stop='^#
Spero che vada a beneficio anche degli altri.
Cin cin.
;
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 Dopo la risposta di Telemaco, le cose hanno iniziato a riversarsi. Funziona come la soluzione che sto cercando dopo tutto.
- Sto cercando di estrarre le linee delimitate da due stringhe (una, con una linea che termina con " CINFILE = " ;; altro, con una linea contenente un singolo " # ") in righe separate, escluso il delimitatore Linee. Questo posso farlo con la soluzione di Telemaco.
- La prima riga ha uno spazio che voglio rimuovere. Lo sto anche includendo.
- Sto anche cercando di estrarre ogni set di righe in file separati.
Questo funziona per me, anche se il codice può essere classificato come brutto; questo perché al momento sono praticamente un nuovo arrivato in Perl. Comunque qui va:
<*>
Spero che vada a beneficio anche degli altri.
Cin cin.
; }
$found=1;
} else { if($found == 1) { close($output); $counter++; $found=0; } }
}
Spero che vada a beneficio anche degli altri. Cin cin.
Non male per venire da un "nuovo arrivato virtuale". Una cosa che potresti fare è mettere " $ found = 1 " all'interno di " if ($ found == 0) " bloccare in modo da non fare quel compito ogni volta tra $ start e $ stop.
Un'altra cosa che è un po 'brutta, secondo me, è che apri lo stesso gestore di file ogni volta che entri nel blocco $ start / $ stop.
Questo mostra un modo per aggirare questo:
#!/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 Non male per venire da un "nuovo arrivato virtuale". Una cosa che potresti fare è mettere " $ found = 1 " all'interno di " if ($ found == 0) " bloccare in modo da non fare quel compito ogni volta tra $ start e $ stop.
Un'altra cosa che è un po 'brutta, secondo me, è che apri lo stesso gestore di file ogni volta che entri nel blocco $ start / $ stop.
Questo mostra un modo per aggirare questo:
<*>;
}
}
}
# Find block of lines to extract
}