2009-06-17 49 views
3

我正在編寫的perl腳本需要解析具有類似Makefile的連續行的文件。即以空白開始的行是前一行的一部分。用於類Makefile文件的最新Perl解析器

我寫了下面的代碼,但不覺得它很乾淨或Perl-ISH

有很多優勢的情況下(赫克,它​​甚至不使用「重做」!):EOF在奇地點,單行文件,以空行開頭或結尾的文件(或非空行或續行),空文件。我所有的測試用例(和代碼)都在這裏:http://whatexit.org/tal/flatten.tar

你可以寫更清潔,perl-ish,通過我所有測試的代碼嗎?

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

回答

6

如何將整個文件粘貼到內存中並使用正則表達式處理它。更多'完美'。這通過你的測試,是小,整潔:

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

有一兩件事要記住使用這兩個礦山和Mirod的回答是,這將是本地化如果你是在一個更大的一段代碼嵌入此採用了特殊的變量(例如「本地$ /」是個好主意) – 2009-06-17 10:10:31

+0

我剛剛編碼通過測試; - )你說得對。 – mirod 2009-06-17 10:16:44

3

如果你不介意加載在內存中的整個文件,然後在下面的代碼通過測試。 它將行存儲在一個數組中,將每行添加到前一個(繼續)或數組末尾(其他)。

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