Perl создает необъяснимый файл с именем "1" - PullRequest
1 голос
/ 03 апреля 2011

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

sub sort_file {
  $filename = @_;

  print @_;
  print $filename;

  open(SRTINFILE,"<$filename");
  @lines=<SRTINFILE>;
  close(SRTINFILE);

  open(SRTOUTFILE,">$filename");
  @sorted = sort { @aa=split(/ /,$a); @bb=split(/ /,$b); return ($aa[1] <=> $bb[1]); } @lines;
  print SRTOUTFILE @sorted;

  close(SRTOUTFILE);

}

каждый раз, когда эта функция запускается, perl создает файл с именем «1».Понятия не имею почему.Я полный Perl Noob и просто использую его для быстрой и грязной обработки текстовых файлов.Кто-нибудь знает, что не так?

Ответы [ 5 ]

10 голосов
/ 03 апреля 2011

Массив в скалярном контексте соответствует количеству элементов в массиве. Если вы передаете один аргумент функции, следующее присваивает 1 значение $filename.

$filename = @_;

Требуется одно из следующих действий:

$filename = $_[0];
$filename = shift;
($filename) = @_;

Кроме того, вы хотите ограничить область действия переменной функцией, поэтому вы хотите

my $filename = $_[0];
my $filename = shift;
my ($filename) = @_;
(my $filename) = @_;  # Exact same as previous.
2 голосов
/ 03 апреля 2011

Других ответов достаточно, чтобы рассказать вам, почему вы получаете странные ошибки.

Я хотел бы показать вам, как более опытный программист Perl может написать эту подпрограмму.

use warnings;
use strict;
use autodie;

sub sort_file {
  my( $filename ) = @_;

  my @lines;
  {
    # 3 arg open
    open my $in_fh, '<', $filename;
    @lines = <$in_fh>;
    close $in_fh;
  }

  # Schwartzian transform
  my @sorted = map{
    $_->[0]
  } sort {
    $a->[2] <=> $b->[2]
  } map {
    [ $_, split ' ', $_ ]
  } @lines;

  {
    open my $out_fh, '>', $filename;
    print {$out_fh} @sorted;
    close $out_fh;  
  }
}
  • use strict;
    не позволяет использовать переменную, не объявляя ее (помимо прочего).

  • use warnings;
    Сообщает о некотором потенциалеошибки.

  • use autodie;
    Теперь вам не нужно писать open .... or die ....

  • { open ...; @lines = <$fh>; close $fh }
    Ограниченияобласть действия FileHandle.

  • @sorted = map { ... } sort { ... } map { ... } @list
    Это примеры преобразования Шварца , которое уменьшает количество раз, когда значения разделяются,В этом примере это может быть излишним.

2 голосов
/ 03 апреля 2011

Как запутанно. Назначение $filename = @_ таким, какой вы есть, означает, что вы оцениваете массив в скалярном контексте, что означает, что $filename назначено количество элементов в @_. Поскольку вы не проверяете, успешен ли первый вызов open, чтение файла 1, скорее всего, не удастся, но вы все равно продолжите и откроете файл для записи 1. Решение состоит в том, чтобы использовать $filename в контексте массива и начать подпрограмму с ($filename) = @_ или $filename = shift.

Почему вы не используете use strict между прочим?

1 голос
/ 03 апреля 2011

Всегда используйте:

use strict;
use warnings;

Тогда Perl скажет вам, когда вы не в курсе.

Как вы заметили, запись:

$filename = @_;

означает, что переменной с незаданной областью назначается количество элементов в списке аргументов функции, и, поскольку вы передаете один файл, имя созданного файла будет равно «1».

Вы хотели написать:

my($filename) = @_;

Это обеспечивает контекст списка для массива и присваивает $_[0] $filename, игнорируя любые дополнительные аргументы функции.

0 голосов
/ 03 апреля 2011

ОК ... не важно. это только осенило меня. $filename = @_; не имеет смысла. должно быть $filename = @_[0];. Там проходит 2 часа моей жизни. примечание для других perl noobs: будьте осторожны.

...