Domanda

Uno script perl che sto scrivendo deve analizzare un file che ha linee di continuazione come un Makefile. vale a dire le righe che iniziano con uno spazio bianco fanno parte della riga precedente.

Ho scritto il codice qui sotto ma non mi sembra che sia molto pulito o perl-ish (diamine, non usa nemmeno " redo " ;!)

Esistono molti casi limite: EOF in punti dispari, file a riga singola, file che iniziano o finiscono con una riga vuota (o riga non vuota o linea di continuazione), file vuoti. Tutti i miei casi di test (e codice) sono qui: http://whatexit.org/tal/flatten.tar

Puoi scrivere codice più pulito, perl-ish, che supera tutti i miei test?

#!/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;
È stato utile?

Soluzione

Che ne dici di slurping l'intero file in memoria ed elaborarlo usando espressioni regolari. Molto più "perlish". Questo supera i tuoi test ed è molto più piccolo e più ordinato:

#!/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;

Altri suggerimenti

Se non ti dispiace caricare l'intero file in memoria, il codice seguente supera i test. Memorizza le linee in una matrice, aggiungendo ciascuna riga alla precedente (continuazione) o alla fine della matrice (altra).

#!/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] .= 

Se non ti dispiace caricare l'intero file in memoria, il codice seguente supera i test. Memorizza le linee in una matrice, aggiungendo ciascuna riga alla precedente (continuazione) o alla fine della matrice (altra).

<*>; } # yes, continuation, add to last line else { push @out,

Se non ti dispiace caricare l'intero file in memoria, il codice seguente supera i test. Memorizza le linee in una matrice, aggiungendo ciascuna riga alla precedente (continuazione) o alla fine della matrice (altra).

<*>; } # no, add as new line } $, = "\n"; # set output field separator $\ = "\n"; # set output record separator print @out;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top