Frage

Ein Perl-Skript, das ich bin Bedürfnis Schreiben eine Datei zu analysieren, die Fortsetzungszeilen wie ein Makefile hat. d.h. Zeilen, die mit Leerzeichen beginnen, sind Teil der vorhergehenden Zeile.

Ich schrieb den Code unten, aber nicht, wie es das Gefühl ist sehr sauber oder Perl-ish (Heck, es nicht einmal verwenden „Redo“!)

Es gibt viele Grenzfälle: EOF an den ungeraden Plätzen, einzeilig Dateien, Dateien, die mit einer Leerzeile (oder Nicht-Leerzeile oder Weiterleitung), leeren Dateien beginnen oder enden. Alle meine Testfälle (und Code) sind hier: http://whatexit.org/tal/flatten.tar

Können Sie schreiben Reiniger, perl-ish, Code, der alle meine Tests bestanden?

#!/usr/bin/perl -w

use strict;

sub process_file_with_continuations {
    my $processref = shift @_;
    my $nextline;
    my $line = <ARGV>;

    $line = '' unless defined $line;
    chomp $line;

    while (defined($nextline = <ARGV>)) {
        chomp $nextline;
        next if $nextline =~ /^\s*#/;  # skip comments
        $nextline =~ s/\s+$//g;  # remove trailing whitespace
        if (eof()) {  # Handle EOF
            $nextline =~ s/^\s+/ /;
            if ($nextline =~ /^\s+/) {  # indented line
                &$processref($line . $nextline);
            }
            else {
                &$processref($line);
                &$processref($nextline) if $nextline ne '';
            }
            $line = '';
        }
        elsif ($nextline eq '') {  # blank line
            &$processref($line);
            $line = '';
        }
        elsif ($nextline =~ /^\s+/) {  # indented line
            $nextline =~ s/^\s+/ /;
            $line .= $nextline;
        }
        else {  # non-indented line
            &$processref($line) unless $line eq '';
            $line = $nextline;
        }
    }
    &$processref($line) unless $line eq '';
}

sub process_one_line {
    my $line = shift @_;
    print "$line\n";
}

process_file_with_continuations \&process_one_line;
War es hilfreich?

Lösung

Wie wäre es die gesamte Datei in den Speicher schlürfen und mit regulären Ausdrücken zu verarbeiten. Viel mehr ‚Perlish‘. Dies geht Ihre Tests und ist viel kleiner und übersichtlicher:

#!/usr/bin/perl

use strict;
use warnings;

$/ = undef;             # we want no input record separator.
my $file = <>;          # slurp whole file

$file =~ s/^\n//;       # Remove newline at start of file
$file =~ s/\s+\n/\n/g;  # Remove trailing whitespace.
$file =~ s/\n\s*#[^\n]+//g;     # Remove comments.
$file =~ s/\n\s+/ /g;   # Merge continuations

# Done
print $file;

Andere Tipps

Wenn Sie nichts dagegen nicht die gesamte Datei in den Speicher geladen, dann geht der folgende Code die Tests. Es speichert die Leitungen in einem Array, das Hinzufügen jede Zeile entweder mit der vorhergehenden (Fortsetzung) oder am Ende des Arrays (andere).

#!/usr/bin/perl

use strict;
use warnings;

my @out;

while( <>)
  { chomp;
    s{#.*}{};             # suppress comments
    next unless( m{\S});  # skip blank lines
    if( s{^\s+}{ })       # does the line start with spaces?
      { $out[-1] .= $_; } # yes, continuation, add to last line
    else 
      { push @out, $_;  } # no, add as new line
  }

$, = "\n";                # set output field separator
$\ = "\n";                # set output record separator
print @out;          
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top