Суммирование столбца чисел в текстовом файле с использованием Perl - программирование
Подтвердить что ты не робот

Суммирование столбца чисел в текстовом файле с использованием Perl

Хорошо, поэтому я очень новичок в Perl. У меня есть текстовый файл, а в файле есть 4 столбца данных (дата, время, размер файлов, файлов). Мне нужно создать небольшой script, который может открыть файл и получить средний размер файлов. Я читал так много онлайн, но я все еще не могу понять, как это сделать. Это то, что у меня есть до сих пор, но я не уверен, что я даже близко делаю это правильно.

#!/usr/bin/perl

open FILE, "files.txt";
#@array = File;

while(FILE){
    #chomp;

    ($date, $time, $numbers, $type) = split(/ /,<FILE>);

    $total += $numbers;

}
print"the total is $total\n";

Так выглядят данные в файле. Это лишь некоторые из них. Мне нужно получить числа в третьем столбце.

12/02/2002  12:16 AM              86016 a2p.exe
10/10/2004  11:33 AM               393 avgfsznew.pl
11/01/2003  04:42 PM             38124 c2ph.bat
4b9b3361

Ответ 1

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

  • Всегда используйте use strict и use warnings в начале вашей программы и объявляйте все свои переменные с помощью my. Это поможет вам найти много простых ошибок, которые вы могли бы игнорировать.

  • Используйте лексические файловые дескрипторы, трехпараметрическую форму open и всегда проверяйте статус возврата любого вызова open

  • Объявить переменную $total вне цикла. Объявление внутри цикла означает, что он будет создан и уничтожен каждый раз вокруг цикла, и он не сможет скопировать общий

  • Объявить переменную $count таким же образом. Он понадобится для вычисления среднего значения

  • Используя while (FILE) {...} просто тесты, которые FILE истинны. Вам нужно прочитать это вместо этого, поэтому вы должны использовать оператор readline, например <FILE>

  • Вы хотите, чтобы вызов по умолчанию был split (без каких-либо параметров), который вернет все непространственные поля в $_ в виде списка

  • Вам нужно добавить переменную в присваивание, чтобы разрешить использовать поля athe AM или PM в каждой строке

Вот модификация вашего кода, который отлично работает

use strict;
use warnings;

open my $fh, '<', "files.txt" or die $!;

my $total = 0;
my $count = 0;

while (<$fh>) {

    my ($date, $time, $ampm, $numbers, $type) = split;

    $total += $numbers;
    $count += 1;

}

print "The total is $total\n";
print "The count is $count\n";
print "The average is ", $total / $count, "\n";

Выход

The total is 124533
The count is 3
The average is 41511

Ответ 2

Заманчиво использовать Perl awk -подобный вариант автоматического разделения. Есть 5 столбцов; три, содержащие информацию о дате и времени, затем размер и имя.

Первая версия script, которую я написал, также является самой многословной:

perl -n -a -e '$total += $F[3]; $num++; END { printf "%12.2f\n", $total / ($num + 0.0); }'

Параметр -a (авторасширение) разбивает строку на пробел в массив @F. В сочетании с опцией -n (которая заставляет Perl работать в цикле, который поочередно считывает аргументы имени файла или стандартный ввод, без печати каждой строки), код добавляет $F[3] (четвертый столбец, считая от 0) до $total, который автома- тически инициализируется нулем при первом использовании. Он также подсчитывает строки в $num. Блок END выполняется, когда считывается все входные данные; он использует printf() для форматирования значения. + 0.0 гарантирует, что арифметика выполняется с плавающей точкой, а не с целочисленной арифметикой. Это очень похоже на awk script:

awk '{ total += $4 } END { print total / NR }'

Первые проекты программ редко бывают оптимальными - или, по крайней мере, я не так хорош программист. Помощь по пересмотру.

Perl был разработан, в частности, как убийца awk. По-прежнему существует программа a2p, распределенная с Perl для преобразования скриптов awk в Perl (а также s2p для преобразования скриптов sed в Perl). И Perl имеет автоматическую (встроенную) переменную, которая отслеживает количество прочитанных строк. У него несколько имен. Терстером является $.; мнемоническое имя $NR доступно, если вы use English; в script; так что $INPUT_LINE_NUMBER. Таким образом, использование $num не требуется. Также выясняется, что Perl все равно выполняет разделение с плавающей запятой, поэтому часть + 0.0 не нужна. Это приводит к следующим версиям:

perl -MEnglish -n -a -e '$total += $F[3]; END { printf "%12.2f\n", $total / $NR; }'

или

perl -n -a -e '$total += $F[3]; END { printf "%12.2f\n", $total / $.; }'

Вы можете настроить формат печати в соответствии с вашими прихотями и фантазиями. Это, по существу, script я буду использовать в долгосрочной перспективе; это довольно ясно, без каких-либо причин. script можно разделить на несколько строк, если хотите. Задача достаточно простая, чтобы разборчивость одной строки не была проблемой, IMNSHO. И красота этого заключается в том, что вам не нужно futz с split и массивов и читать петли самостоятельно; Perl делает большую часть этого для вас. (Конечно, он взорвется на пустом входе, это исправление тривиально, см. Ниже.)

Рекомендуемая версия

perl -n -a -e '$total += $F[3]; END { printf "%12.2f\n", $total / $. if $.; }'

if $. проверяет, является ли число прочитанных строк нулевым или нет; printf и деление опущены, если $. равно нулю, поэтому script ничего не выводит при отсутствии ввода.


Существует благородная (или неблагородная) игра под названием "Code Golf", которую играли в первые дни Stack Overflow, но вопросы Code Golf больше не считаются хорошими. Цель Code Golf - написать программу, которая выполняет определенную задачу как можно меньше символов. Вы можете играть в Code Golf с этим и сжимать его еще дальше, если вы не слишком беспокоитесь о формате вывода и используете хотя бы Perl 5.10:

perl -Mv5.10 -n -a -e '$total += $F[3]; END { say $total / $. if $.; }'

И, очевидно, в нем много лишних пробелов и букв:

perl -Mv5.10 -nae '$t+=$F[3];END{say$t/$.if$.}'

Это не так ясно, как рекомендуемая версия.

Ответ 3

#!/usr/bin/perl

use warnings;
use strict;

open my $file, "<", "files.txt";
my ($total, $cnt);
while(<$file>){
        $total += (split(/\s+/, $_))[3];
        $cnt++;
}
close $file;
print  "number of files: $cnt\n";
print  "total size: $total\n";
printf "avg: %.2f\n", $total/$cnt;

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

awk '{t+=$4} END{print t/NR}' files.txt

Ответ 4

Попробуйте сделать это:

#!/usr/bin/perl -l

use strict; use warnings;

open my $file, '<', "my_file" or die "open error [$!]";

my ($total, $count);

while (<$file>){
    chomp;
    next if /^$/;
    my ($date, $time, $x, $numbers, $type) = split;
    $total += $numbers;
    $count++;
}

print "the average is " . $total/$count . " and the total is $total";

close $file;

Ответ 5

Это решение открывает файл и проходит через каждую строку файла. Затем он разбивает файл на пять переменных в строке путем разделения на 1 или более пробелов.

  • откройте файл для чтения, "<", и если он сбой, поднимите сообщение об ошибке or die "..."
  • my ($total, $cnt) - общее количество столбцов и количество добавленных файлов
  • while(<FILE>) { ... } проходит через каждую строку файла с помощью дескриптора файла и сохраняет строку в $_
  • chomp удаляет разделитель входных данных в $_. В unix разделитель по умолчанию представляет собой новую строку \n
  • split(/\s+/, $_) Разделяет текущую строку, представленную $_, с разделителем \s+. \s представляет собой пробел, + после этого означает "1 или более". Итак, мы разделили следующую строку на 1 или более пробелов.
  • Затем мы обновляем $total и $cnt

    #!/usr/bin/perl
    
    open FILE, "<", "files.txt" or die "Error opening file: $!";
    my ($total, $cnt);
    
    while(<FILE>){
      chomp;
      my ($date, $time, $am_pm, $numbers, $type) = split(/\s+/, $_); 
      $total += $numbers;
      $cnt++; 
    }
    close FILE;
    
    print"the total is $total and count of $cnt\n";`
    

Ответ 6

Это так просто:

perl -F -lane '$a+=$F[3];END{print "The average size is ".$a/$.}' your_file

проверено ниже:

> cat temp
12/02/2002  12:16 AM              86016 a2p.exe
10/10/2004  11:33 AM               393 avgfsznew.pl
11/01/2003  04:42 PM             38124 c2ph.bat

Теперь выполнение:

> perl -F -lane '$a+=$F[3];END{print "The average size is ".$a/$.}' temp
The average size is 41511
> 

Объяснение: -F -a говорит, что сохраняет строку в формате массива. С разделителем по умолчанию в качестве пробела или вкладки. поэтому nopw $F [3] имеет размер файла. суммируйте все размеры в 4-м столбце до тех пор, пока все строки не будут обработаны. END будет выполнен после обработки всех строк в файле.

so $. в конце будет указано количество строк. поэтому $a/$. даст среднее значение.