Perl: распечатка файла, в котором встречается слово

#perl #indexing

#perl #индексирование

Вопрос:

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

Однако я затрудняюсь со второй частью, а именно с поиском, в каком файле (т. Е. имени файла) встречается это слово. Я подумываю об использовании массива, в котором хранится слово, но не знаю, лучший ли это способ или какой самый лучший способ. Это код, который у меня есть на данный момент, и, похоже, он хорошо работает для той части, которая подсчитывает, сколько раз слово встречается в данном файле (ах):

 use strict;
use warnings;

my %count;

while (<>) {

  my $casefoldstr = lc $_;

  foreach my $str ($casefoldstr =~ /w /g) {
    $count{$str}  ;
  }
}

foreach my $str (sort keys %count) {
  printf  "$str $count{$str}:n";
}
  

Комментарии:

1. Я исправил отступ в вашем коде. Я постоянно удивляюсь, как много людей пытаются писать код с кажущимися случайными отступами!

2. perltidy -pbp фтв!

3. Это очень помогло бы, если бы вы показали тот результат, который вы хотели.

Ответ №1:

Доступ к имени файла осуществляется через $ARGV .

Вы можете использовать это для создания вложенного хэша с именем файла и словом в качестве ключей:

 use strict;
use warnings;
use List::Util 'sum';

while (<>) {
    $count{$word}{$ARGV}   for map  lc, /w /g;
}

foreach my $word ( keys %count ) {

    my @files = keys %$word;  # All files containing lc $word
    print "Total word count for '$word': ", sum( @{ $count{$word} }{@files} ), "n";

    for my $file ( @files ) {
        print "$count{$word}{$file} counts of '$word' detected in '$file'n";
    }
}
  

Комментарии:

1. Каким должен быть результат, если один и тот же файл предоставляется дважды?

2. @reinierpost если один и тот же файл будет предоставлен дважды, количество слов для этого файла удвоится. Этот конкретный сценарий (и вызывающий удивление?) может быть смягчен предварительной обработкой @ARGV до того, как он попадет в while цикл: use List::Util qw(sum uniq); BEGIN { @ARGV = uniq @ARGV }

3. Или путем печати и очистки хэша на eof .

Ответ №2:

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

 #!/usr/bin/perl
use warnings;
use strict;

my %count;
my %in_file;
while (<>) {
    my $casefoldstr = lc;
    for my $str ($casefoldstr =~ /w /g) {
          $count{$str};
        push @{ $in_file{$str} }, $ARGV
            unless ref $in_file{$str} amp;amp; $in_file{$str}[-1] eq $ARGV;
    }
}

foreach my $str (sort keys %count) {
    printf  "$str $count{$str}: @{ $in_file{$str} }n";
}