Как можно избежать предупреждений Perl :: Critic при обработке многострочной строки с помощью дескриптора файла? - PullRequest
2 голосов
/ 09 октября 2009

Есть ли у кого-нибудь решение задачи по обработке многострочной строки по одной строке за раз, кроме решения со строкой-как-файлом-дескриптором, показанного ниже?

my $multiline_string = "line one\nline two\nline three\nline four";
my $filehandle;
open( $filehandle, '<', \$multiline_string )
    or croak("Can't open multi-line string as a filehandle: $!");
while ( defined (my $single_line = <$filehandle>) ) {
    # do some processing of $single_line here ...
}
close( $filehandle );

Моя причина отказа от использования файлового дескриптора довольно слабая. Test :: Perl :: Critic скулит, когда у меня есть более 10 строк исходного кода между моей командой open и командой close в любом дескрипторе файла. Я немного занимаюсь обработкой $ single_line, так что на самом деле у меня есть около 40 строк кода между моим открытым вызовом и моим закрытым вызовом, и я не вижу способа снизить это значение до 10.

И я действительно не хочу игнорировать тест Perl :: Critic в моей сборке, потому что это действительно достойный тест, который я хотел бы пройти, когда я открываю фактический файл на диске в своем коде.

Ответы [ 8 ]

9 голосов
/ 09 октября 2009

Сделайте Perl Critic счастливым и сделайте себя еще счастливее, создав подпрограмму и вызывая ее для каждой строки файла.

use strict; use warnings;

sub do_something {
    my ($line) = @_;
    # do something with $line
}

open my $fh, '<', \$multiline_string
    or die "Cannot open scalar for reading: $!";

while(<$fh>) {
    chomp;
    do_something($_);
}

close $fh; 
5 голосов
/ 09 октября 2009

Хм, разве не цель скулить, чтобы заставить вас иметь меньшие блоки кода, которые делают только одну вещь? создайте подпрограмму, которая делает то, что нужно для каждой строки.

Многие люди предложили split /\n/. split /^/ больше похоже на способ обработки файлов.

3 голосов
/ 09 октября 2009

Задолго до того, как я узнал, что вы можете вставить многострочную строку в дескриптор файла, было split:

foreach my $single_line (split /\n/, $multiline_string) {
    # process $single_line here
    # although note that it doesn't end in a newline anymore
}

Вставьте здесь отказ от ответственности об использовании буквального и непереносимого \n здесь.

3 голосов
/ 09 октября 2009

Я мог бы что-то упустить, но вы могли бы сделать:

my @lines = split(/\n/,$multiline_string);
foreach my $single_line (@lines) {
  ...
}
3 голосов
/ 09 октября 2009

А как же:

my $multiline_string = "line one\nline two\nline three\nline four";
my @lines = split(/\n/,$multiline_string);
foreach my $line (@lines) {
    #do stuff with string
}
2 голосов
/ 09 октября 2009

Perl :: Critic это хорошо, но когда вы начинаете зацикливаться на некоторых своих произвольных требованиях, он начинает тратить ваше время, а не сохранять. Я просто позволил дескриптору файла выйти из области видимости и не беспокоиться о закрытии:

 my $multiline_string = "line one\nline two\nline three\nline four";

 {
     open my( $fh ), '<', \$multiline_string )
         or croak("Can't open multi-line string as a filehandle: $!");
     while ( defined (my $single_line = <$fh>) ) {
         # do some processing of $single_line here ...
     }
 }

Многие люди тянутся к регулярным выражениям или разделению, но я думаю, что это небрежно. Вам не нужно создавать новый список и использовать намного больше памяти в вашей программе.

0 голосов
/ 09 октября 2009

Лично мне нравится использовать $/ для разделения строк в многострочной строке.

my $multiline_string = "line one\nline two\nline three\nline four";
foreach (split($/, $mutliline_string)) {
  process_file($_);
}
sub process_file {
  my $filename = shift;
  my $filehandle;
  open( $filehandle, '<', $filename )
      or croak("Can't open multi-line string as a filehandle: $!");
  while ( defined (my $single_line = <$filehandle>) ) {
      process_line($single_line);
  }
  close( $filehandle );
}
sub process_line {
  my $line = shift;
  ...
}
0 голосов
/ 09 октября 2009

Вы можете использовать регулярное выражение.

#!/usr/bin/perl

use strict;
use warnings;

my $s = "line one\nline two\nline three\nline four";

while ($s =~ m'^(.*)$'gm) {
    print "'$1'\n";
}

die "Exited loop too early\n" unless pos $s == length $s;

Или вы можете использовать split:

for my $line ( split m'\n', $multiline_string ){

  # ...

}
...