Я собираюсь игнорировать заголовок вашего вопроса и сосредоточиться на части кода, который вы разместили, потому что это положительно вредно, если оставить этот код без объяснения, что с ним не так. Вы говорите:
код, который может печатать совпадающие строки со строками непосредственно над ними. Код, который частично соответствует моей цели, выглядит примерно так:
Я собираюсь пройти через этот код. Во-первых, вы всегда должны включать
use strict;
use warnings;
в ваших сценариях, тем более что вы только изучаете Perl.
@array;
Это бессмысленное утверждение. С помощью strict
вы можете объявить @array
, используя:
my @array;
Предпочитайте форму с тремя аргументами open
, если в конкретной ситуации нет особой выгоды от ее неиспользования. Используйте лексические файловые дескрипторы, потому что файловые дескрипторы голых слов являются глобальными пакетами и могут быть источником загадочных ошибок. Наконец, всегда проверяйте, удалось ли open
, прежде чем продолжить. Итак, вместо:
open(FH, "FILE");
запись:
my $filename = 'something';
open my $fh, '<', $filename
or die "Cannot open '$filename': $!";
Если вы используете autodie , вы можете сойти с:
open my $fh, '<', 'something';
Двигаемся дальше:
while ( <FH> ) {
chomp;
$my_line = "$_";
Сначала прочитайте FAQ (это нужно было сделать перед тем, как начать писать программы). См. Что плохого в том, чтобы всегда цитировать "$ vars"? . Во-вторых, если вы собираетесь присвоить строку, которую вы только что прочитали, $my_line
, вы должны сделать это в операторе while
, чтобы не нажимать на $_
. Наконец, вы можете быть strict
совместимым, не вводя больше символов:
while ( my $line = <$fh> ) {
chomp $line;
Снова обратитесь к предыдущему FAQ.
if ("$my_line" =~ /Pattern/) {
Зачем интерполировать $my_line
еще раз?
foreach( @array ){
print "$_\n";
}
Либо используйте явную переменную цикла, либо превратите ее в:
print "$_\n" for @array;
Итак, вы интерполируете $my_line
снова и добавляете новую строку, которая была удалена chomp
ранее. Нет причин делать это:
print "$my_line\n"
А теперь мы подошли к линии, которая побудила меня разбирать код, который вы в первую очередь разместили:
if ( "$#array" > "0" ) {
$#array
- это число . 0
- это число . >
используется для проверки, больше ли число на LHS, чем число на RHS. Следовательно, нет необходимости преобразовывать оба операнда в строки.
Далее, $#array
является последним индексом @array
, и его значение зависит от значения $[
. Я не могу понять, что это утверждение должно проверять.
Итак, ваша первоначальная постановка задачи была
печатать совпадающие строки с линиями непосредственно над ними
Естественный вопрос, конечно, состоит в том, сколько строк «непосредственно над» соответствием вы хотите напечатать.
#!/usr/bin/perl
use strict;
use warnings;
use Readonly;
Readonly::Scalar my $KEEP_BEFORE => 4;
my $filename = $ARGV[0];
my $pattern = qr/$ARGV[1]/;
open my $input_fh, '<', $filename
or die "Cannot open '$filename': $!";
my @before;
while ( my $line = <$input_fh> ) {
$line = sprintf '%6d: %s', $., $line;
print @before, $line, "\n" if $line =~ $pattern;
push @before, $line;
shift @before if @before > $KEEP_BEFORE;
}
close $input_fh;