Как написать это лучше в Perl - PullRequest
5 голосов
/ 02 марта 2012

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

02/26/2012 08:54:38 Error:java.sql.Exception
02/26/2012 08:54:48 Error:java.sql.Exception
02/26/2012 08:56:05 Error:java.sql.Exception
02/26/2012 08:57:21 Error:java.sql.Exception
02/26/2012 08:59:29 Error:java.sql.Exception
02/26/2012 09:01:14 Error:java.sql.Exception
02/26/2012 09:08:48 Error:java.sql.Exception
02/26/2012 09:10:41 Error:java.sql.Exception

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

02/26/2012 08 -> 5
02/26/2012 09 -> 3

Вот скрипт, который работает для меня:

#!/bin/perl
open(MYFILE, 'tata2');
my %table;
while (<MYFILE>) {
     chomp;
     $dtkey = substr $_, 0, 13;
     $table{$dtkey}++;
}
close(MYFILE); 
for my $key (keys %table) {
    print "$key -> $table{$key}\n";
}

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

Ответы [ 3 ]

6 голосов
/ 02 марта 2012

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

Вот переписывание с использованием некоторых других синтаксических возможностей Perl:

open my $fh, '<', 'filename' or die $!;
my %table;

while (<$fh>) {
    $table{$1}++ if /([^:]+)/ # regex is a bit shorter than the substr
}

print "$_ -> $table{$_}\n" for keys %table;  # statement modifier form

Или, если вы действительно хотите, чтобы это было коротко, как насчет одного вкладыша:

perl -lnE '$t{$1}++ if /([^:]+)/; END {say "$_ -> $t{$_}" for keys %t}' infile
2 голосов
/ 02 марта 2012

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

Выможно обойтись без цифр и создать именованные группы захвата.Обозначение: (?<name>...) для объявления и \g{name} для ссылки.(Чтобы быть совместимым с регулярными выражениями .NET, \g{name} также может быть записано как \k{name}, \k<name> или \k'name'.) имя не должно начинаться с цифры или содержать дефисы.Если разные группы в одном и том же шаблоне имеют одно и то же имя, любая ссылка на это имя предполагает наличие самой левой определенной группы.Именованные группы учитываются в абсолютной и относительной нумерации, поэтому по этим номерам также можно ссылаться.(Можно делать вещи с именованными группами захвата, которые в противном случае потребовали бы (??{}).)

Содержимое группы захвата динамически ограничено и доступно вам за пределами шаблона до конца включающего блока или до следующего успешногоматч, в зависимости от того, что наступит раньше.(См. Сложные заявления в perlsyn.) Вы можете ссылаться на них по абсолютному числу (используя $1 вместо \g1 и т. Д.);или по имени через %+ хэш , используя $+{name}.

Для каждой строки ввода ищите совпадение, но переставляйте компоненты в YYYY / MM / DDHH заказ для легкой сортировки.

#! /usr/bin/env perl

use strict;
use warnings;

use 5.10.0;  # named capture buffers

*ARGV = *DATA;  # for demo only; remove for real use

my %hour_errors;
while (<>) {
  $hour_errors{"$+{y}/$+{m}/$+{d} $+{h}"}++
    if m!^ (?<m> \d+) / (?<d> \d+) / (?<y> \d+)  \s+  (?<h> \d+) :!x;
}

print "$_ -> $hour_errors{$_}\n" for sort keys %hour_errors;

__DATA__
02/26/2012 08:54:38 Error:java.sql.Exception
02/26/2012 08:54:48 Error:java.sql.Exception
02/26/2012 08:56:05 Error:java.sql.Exception
02/26/2012 08:57:21 Error:java.sql.Exception
02/26/2012 08:59:29 Error:java.sql.Exception
02/26/2012 09:01:14 Error:java.sql.Exception
02/26/2012 09:08:48 Error:java.sql.Exception
02/26/2012 09:10:41 Error:java.sql.Exception

Выход:

2012/02/26 08 -> 5
2012/02/26 09 -> 3
1 голос
/ 03 марта 2012

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

use Tie::IxHash;
tie my %table, 'Tie::IxHash';
$table{substr $_, 0, 13}++ while <DATA>;
print "$_ -> $table{$_}\n" for keys %table;
__DATA__
02/26/2012 09:10:41 Error:java.sql.Exception
02/26/2012 08:54:38 Error:java.sql.Exception
02/26/2012 08:54:48 Error:java.sql.Exception
02/26/2012 08:56:05 Error:java.sql.Exception
02/26/2012 08:57:21 Error:java.sql.Exception
02/26/2012 08:59:29 Error:java.sql.Exception
02/26/2012 09:01:14 Error:java.sql.Exception
02/26/2012 09:08:48 Error:java.sql.Exception
02/26/2012 09:10:41 Error:java.sql.Exception
03/26/2012 08:54:38 Error:java.sql.Exception
03/26/2012 08:54:48 Error:java.sql.Exception
03/26/2012 08:56:05 Error:java.sql.Exception
03/26/2012 08:57:21 Error:java.sql.Exception
03/26/2012 08:59:29 Error:java.sql.Exception
03/26/2012 09:01:14 Error:java.sql.Exception
03/26/2012 09:08:48 Error:java.sql.Exception
04/26/2012 08:54:38 Error:java.sql.Exception
04/26/2012 08:54:48 Error:java.sql.Exception
04/26/2012 08:56:05 Error:java.sql.Exception
04/26/2012 08:57:21 Error:java.sql.Exception
04/26/2012 08:59:29 Error:java.sql.Exception
04/26/2012 09:01:14 Error:java.sql.Exception
04/26/2012 09:08:48 Error:java.sql.Exception
04/26/2012 09:10:41 Error:java.sql.Exception

Если у вас нет доступа к Tie :: IxHash, то вот короткая версия с сортировкой ключей (минус повторение ДАННЫЕ ).

my %table;
$table{substr $_, 0, 13}++ while <DATA>;
print "$_ -> $table{$_}\n" for sort { "@{[($a=~/(\d+)\D?/g)[2,1,0,3]]}" cmp "@{[($b=~/(\d+)\D?/g)[2,1,0,3]]}" } keys %table;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...