Wie extrahiere ich Linien zwischen zwei Zeilenbegrenzungszeichen in Perl?
Frage
Ich habe eine ASCII-Protokolldatei mit einigen Inhalten würde ich extrahieren möchte. Ich habe nie die Zeit genommen Perl richtig zu lernen, aber ich glaube dies ein gutes Werkzeug für diese Aufgabe ist.
Die Datei wird wie folgt strukturiert:
... ... 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
Also, ich bin auf der Suche nach einer Möglichkeit, die Linien zwischen den einzelnen START
und END
Begrenzer Strings zu extrahieren.
Wie kann ich das tun?
Bisher hat ich finde nur einige Beispiele dafür, wie eine Zeile mit dem START
String oder anderer Dokumentation Artikeln zu drucken, die etwas im Zusammenhang mit dem, was ich suche.
Lösung
Sie möchten die Flip-Flop-Operator (besser als der Bereich Operator bekannt) ..
#!/usr/bin/env perl
use strict;
use warnings;
while (<>) {
if (/START/../END/) {
next if /START/ || /END/;
print;
}
}
Ersetzen Sie den Aufruf mit print
, was Sie wirklich wollen, tun (zum Beispiel, drücken Sie die Zeile in einem Array, bearbeiten, formatieren Sie ihn, was auch immer). Ich bin next
-ing vorbei an den Linien, die tatsächlich START
oder END
haben, aber Sie können nicht dieses Verhalten möchten. Siehe diesem Artikel für eine Diskussion dieses Operators und andere nützliche Perl spezielle Variablen.
Andere Tipps
perlfaq6 's Antwort auf
Wie kann ich packen mehr Linien nach einer passenden Zeile in Perl? Wie ist das ein? In diesem einen ist die END string $ ^, können Sie es zu Ihrem END Zeichenfolge ändern können. Ich bin auch ein Neuling, aber die Lösungen dort schon einige Methoden bieten ... lassen Sie mich wissen, genauer gesagt, was Sie wollen, dass aus den obigen Link abweicht.
while (<>) {
chomp; # strip record separator
if(/END/) { $f=0;}
if (/START/) {
s/.*START//g;
$f=1;
}
print $_ ."\n" if $f;
}
versuchen einige Code beim nächsten Mal schreiben
Nach dem Telemachos Antwort, begann Dinge Ausgießen. Dies funktioniert wie die Lösung auf, nachdem alles, was ich bin auf der Suche.
- Ich versuche Linien von zwei Strings begrenzt zu extrahieren (eines, mit einer Linie mit der Endung „CINFILE =“; andere, mit einer Linie eines einzigen „#“ enthält) in getrennten Linien, mit Ausnahme der Begrenzungslinien. Das kann ich Lösung mit Telemachos tun.
- Die erste Zeile hat einen Raum, den ich entfernen möchten. Ich schließe es auch.
- Ich versuche auch jede Zeile-Set in separate Dateien zu extrahieren.
Dies funktioniert für mich, obwohl der Code kann als hässlich eingestuft werden; dies liegt daran, dass ich zur Zeit ein praktisch Neuling in Perl bin. Auf jeden Fall hier geht:
#!/usr/bin/env perl
use strict;
use warnings;
my $start='CINFILE=$';
my $stop='^#$';
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 $_; }
$found=1;
} else { if($found == 1) { close($output); $counter++; $found=0; } }
}
Ich hoffe, dass es auch andere Vorteile. Prost.
Nicht schlecht für von einem „virtuellen Newcommer“ kommen. Eine Sache, die Sie tun können, ist, die setzen „gefunden $ = 1“ innerhalb des „if ($ gefunden == 0)“ Block, so dass Sie nicht, dass die Zuordnung tun, jedes Mal zwischen $ beginnen und $ stoppen.
Ein andere Sache, die ein bisschen hässlich, meiner Meinung nach ist, ist, dass Sie die gleichen Filehandler jedes Mal, wenn der $ Start / $ Stop-Blockes eingeben öffnen.
Dies zeigt eine Art und Weise um, dass:
#!/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 $_;
}
}
}
# Find block of lines to extract
}