2013-12-14 4 views
1

Я новичок в perl и не очень хорошо разбираюсь в структурах данных. Я работал над текстовым анализатором, чтобы извлечь информацию из текстового файла и сохранить его в базе данных. Регулярные шаблоны теперь одобрены, но я только заметил, что ключ, который я использовал для моего хэша «Время» не уникален, так как в нем есть несколько обновлений (в текстовом файле), которые могут произойти одновременно. То, что делает хэш, создает дубликаты, неприемлемые для моей цели. Поэтому я думал добавить еще один ключ, возможно, уникальный счетчик, но я не знаю, как это сделать. Таким образом, я пытался добавить еще один ключевой «{$ recordcnt}» в качестве счетчика вы увидите, что добавляется на всех хэш statements.I удаляемого операторы счетчика приращения (возможно я не правильно реализовать)Perl Parser using Hash

Кроме того, если вы посмотрите на блок оператора печати (последний раздел) моего кода, я пытаюсь распечатать, получить массив (@nodes_and_index) значение, которое содержит два столбца узлов и индекса, печатать и отображать их по-разному. Однако он не печатает желаемые результаты. Было тестирование, предполагая, что я хотел бы вводить данные в базу данных отдельно.

Итак, я поставил «{$ recordcnt}» в неправильных местах, если это так. Как сделать каждую запись уникальной в хэш со временем? Спасибо за прочтение.

Это пример моих данных:

TIME: 11/01/13 14:30:24 
FROM: 10.255.9.4 AS172193 
TO: 10.255.9.10 AS676767 
ASPATH: 172193 19601 14835 1286 577 4097 2841 14735 9486 573 10633 4488 
NEXT_HOP: 10.255.9.126 
ANNOUNCE 
    10.44.193.0/24 

TIME: 11/01/13 14:30:24 
FROM: 10.255.9.4 AS172193 
TO: 10.255.9.10 AS676767 
ASPATH: 172193 19601 14835 4758 2379 10721 10787 7830 17777 4875 4488 
NEXT_HOP: 10.255.9.126 
ANNOUNCE 
    10.44.193.0/24 

TIME: 11/01/13 14:30:25 
FROM: 10.255.9.4 AS172193 
TO: 10.255.9.10 AS676767 
ASPATH: 172193 19601 14835 4758 2379 10721 10787 7830 17777 16480 9486 573 10633 4488 
NEXT_HOP: 10.255.9.126 
ANNOUNCE 
    10.44.193.0/24 

TIME: 11/01/13 14:30:25 
FROM: 10.255.9.4 AS172193 
TO: 10.255.9.10 AS676767 
ASPATH: 172193 19601 19602 3252 3665 2315 2379 10721 7311 12934 4875 4488 
NEXT_HOP: 10.255.9.125 
ANNOUNCE 
    10.44.193.0/24 

TIME: 11/01/13 14:30:34 
FROM: 10.255.9.4 AS172193 
TO: 10.255.9.10 AS676767 
ASPATH: 172193 19601 19602 3252 3665 2315 2379 3725 
NEXT_HOP: 10.255.9.125 
ANNOUNCE 
    10.44.193.0/24 

Это мой полный код:

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

my %hash; 
my $Dir = "/root/updates/processed/"; 
my $exit = 0; 
my $recordcnt = 0 ; 
opendir(DIRECTORY, $Dir) or die $!; 

while (my $file = readdir(DIRECTORY)) { 

    unless ($file=~/\.hr$/){next;} 


    my $file = $Dir."/".$file; 
    print "$file\n"; 

    open (IN, $file) or die "error reading file: ", $file,"\n"; 

    my $record_id = ""; 
    #my $recordcnt = 0 ; 
    my $type = ""; 
    my $peer_ip = ""; 
    my $peer_as = ""; 
    my $local_ip = ""; 
    my $local_as = ""; 
    my $next_hop = ""; 
    my @nodes_and_index =(); 
    my @withdraw_prefix =(); 
    my @announce_prefix =(); 



    while (<IN>) {   

     #$exit++; last if ($exit==5); 

     if (/^TIME/) { 

      if ($type) {$hash{$record_id}{$recordcnt}{'type'} = $type;} 
      if ($peer_ip) {$hash{$record_id}{$recordcnt}{'peer_ip'} = $peer_ip;} 
      if ($peer_as) {$hash{$record_id}{$recordcnt}{'peer_as'} = $peer_as;} 
      if ($local_ip) {$hash{$record_id}{$recordcnt}{'local_ip'} = $local_ip;} 
      if ($local_as) {$hash{$record_id}{$recordcnt}{'local_as'} = $local_as;} 
      if ($next_hop) {$hash{$record_id}{$recordcnt}{'next_hop'} = $next_hop;} 

      if (@nodes_and_index) {push @{$hash{$record_id}{$recordcnt}{'nodes_and_index'}}, @nodes_and_index;} 
      if (@withdraw_prefix) {push @{$hash{$record_id}{$recordcnt}{'withdraw_prefix'}}, @withdraw_prefix;} 
      if (@announce_prefix) {push @{$hash{$record_id}{$recordcnt}{'announce_prefix'}}, @announce_prefix;} 

      $peer_as = ""; 
      $peer_ip = ""; 
      $type = ""; 
      $local_ip = ""; 
      $local_as = ""; 
      $next_hop = ""; 
      $record_id = ""; 
      $recordcnt = 0; 
      @nodes_and_index =(); 
      @withdraw_prefix =(); 
      @announce_prefix =(); 


      my @time = split '\s', $_; 
      $record_id = $time[1]."_".$time[2]; 

     } elsif (/^FROM/) { 
      my @from_tmp = split '\s', $_; 
      $peer_ip = $from_tmp[1]; 
      $peer_as = $from_tmp[2]; 
      $peer_as =~ s/AS//; 

     } elsif (/^TO/) { 
      my @to_tmp = split '\s', $_; 
      $local_ip = $to_tmp[1]; 
      $local_as = $to_tmp[2]; 
      $local_as =~ s/AS//; 
      #print "$local_ip\n"; 

     } elsif (/^ASPATH/) { 

      my @nodes_tmp = split '\s', $_; 
       shift @nodes_tmp;  
      my $index = 0; 

      foreach my $node (@nodes_tmp) { 
        $index++; 
        push @nodes_and_index, ($node , $index); 
      } 

     }elsif (/^NEXT_HOP/) { 

      my @next_hop_tmp = split '\s', $_; 
      $next_hop = $next_hop_tmp[1]; 

     }elsif (/^WITHDRAW/) { 
      while (<IN>) {  
        last if !/^ +/;  
        @withdraw_prefix, $_ ;    
       } 


     }elsif (/^ANNOUNCE/) { 
       while (<IN>) {   
         last if !/^ +/;  
       push @announce_prefix, $_; 

       } 
      } 


     if ($record_id) { # handle last result 
      $hash{$record_id}{$recordcnt}{'peer_as'} = $peer_as; 
      $hash{$record_id}{$recordcnt}{'peer_ip'} = $peer_ip; 
      $hash{$record_id}{$recordcnt}{'local_as'} = $local_as; 
      $hash{$record_id}{$recordcnt}{'local_ip'} = $local_ip; 
      $hash{$record_id}{$recordcnt}{'next_hop'} = $next_hop; 

      push @{$hash{$record_id}{$recordcnt}{'nodes_and_index'}} ,@nodes_and_index; 
      push @{$hash{$record_id}{$recordcnt}{'withdraw_prefix'}} ,@withdraw_prefix; 
      push @{$hash{$record_id}{$recordcnt}{'announce_prefix'}} ,@announce_prefix; 

     } 
    } 
    close IN; 
} 
my @arraystuff; 
my @separated; 
my @iindex=(); 
my @ppath=(); 
foreach (sort keys %hash) { 

    print $_, "\n"; 
    print "\t $hash{$_}{$recordcnt}{'peer_ip'}\n"; 
    print "\t $hash{$_}{$recordcnt}{'peer_as'}\n"; 
    print "\t $hash{$_}{$recordcnt}{'local_ip'}\n"; 
    print "\t $hash{$_}{$recordcnt}{'local_as'}\n"; 
    print "\t $hash{$_}{$recordcnt}{'next_hop'}\n"; 

    @arraystuff = @{$hash{$_}{$recordcnt}{'nodes_and_index'}}; 
    foreach (@arraystuff) { 
     @separated = split('\s', $_); 
     push @iindex, $separated[1]; 
     push @ppath, $separated[0]; 
     print "\t index: @iindex"; 
     print "\t path: @ppath"; 
     } 


    print "\t node index : @{$hash{$_}{$recordcnt}{'nodes_and_index'}}\n";  
    print "\t withdraw_prefix: @{$hash{$_}{$recordcnt}{'withdraw_prefix'}}\n"; 
    print "\t announce: @{$hash{$_}{$recordcnt}{'announce_prefix'}}\n"; 
} 

============== ================================================== ===================================

Новая версия, рекомендованная Foibs

#!/usr/bin/perl -w 

use strict; 
use warnings; 


my @datasetarray; 
my $Dir = "/root/updates\/processed/"; 
my $exit = 0; 

opendir(DIRECTORY, $Dir) or die $!; 

while (my $file = readdir(DIRECTORY)) { 

    unless ($file=~/\.hr$/){next;} 
    #unless ($file=~/\.txt$/){next;} 

    my $file = $Dir."/".$file; 
    print "$file\n"; 

    open (IN, $file) or die "error reading file: ", $file,"\n"; 

    my $record_id = ""; 
    my $type = ""; 
    my $peer_ip = ""; 
    my $peer_as = ""; 
    my $local_ip = ""; 
    my $local_as = ""; 
    my $next_hop = ""; 
    my @nodes_and_index =(); 
    my @withdraw_prefix =(); 
    my @announce_prefix =(); 


    my $tmphash = {}; 

    while (<IN>) {   

     #$exit++; last if ($exit==5); 

     if (/^TIME/) { 


      if ($type) {$tmphash->{'type'} = $type;} 
      if ($peer_ip) {$tmphash->{'peer_ip'} = $peer_ip;} 
      if ($peer_as) {$tmphash->{'peer_as'} = $peer_as;} 
      if ($local_ip) {$tmphash->{'local_ip'} = $local_ip;} 
      if ($local_as) {$tmphash->{'local_as'} = $local_as;} 
      if ($next_hop) {$tmphash->{'next_hop'} = $next_hop;} 
       #if (@nodes_and_index) {push {$tmphash->{'nodes_and_index'}}, @nodes_and_index;} 
      #if (@withdraw_prefix) {push {$tmphash->{'withdraw_prefix'}}, @withdraw_prefix;} 
      #if (@announce_prefix) {push {$tmphash->{'announce_prefix'}}, @announce_prefix;} 

#The three commented lines above provide error, thus i don't know if i am implementing it the right way, since they are array and different from the others. 

      $peer_as = ""; 
      $peer_ip = ""; 
      $type = ""; 
      $local_ip = ""; 
      $local_as = ""; 
      $next_hop = ""; 
      $record_id = ""; 
      @nodes_and_index =(); 
      @withdraw_prefix =(); 
      @announce_prefix =(); 


      my @time = split '\s', $_; 
      $record_id = $time[1]."_".$time[2]; 


     } elsif (/^TYPE/) { 
      my @type_tmp = split '\s', $_; 
      $type = $type_tmp[1]; 

     } elsif (/^FROM/) { 
      my @from_tmp = split '\s', $_; 
      $peer_ip = $from_tmp[1]; 
      $peer_as = $from_tmp[2]; 
      $peer_as =~ s/AS//; 

     } elsif (/^TO/) { 
      my @to_tmp = split '\s', $_; 
      $local_ip = $to_tmp[1]; 
      $local_as = $to_tmp[2]; 
      $local_as =~ s/AS//; 

     } elsif (/^ASPATH/) { 

      my @nodes_tmp = split '\s', $_; 
       shift @nodes_tmp;  
      my $index = 0; 

      foreach my $node (@nodes_tmp) { 
        $index++; 
      push @nodes_and_index, ($node , $index); 
      } 

     }elsif (/^NEXT_HOP/) { 

      my @next_hop_tmp = split '\s', $_; 
      $next_hop = $next_hop_tmp[1]; 

     }elsif (/^WITHDRAW/) { 
      while (<IN>) {  
        last if !/^ +/;  
        push @withdraw_prefix, $_ ;   

       } 


     }elsif (/^ANNOUNCE/) { 

       while (<IN>) {   
        last if !/^ +/;  
        push @announce_prefix, $_; 

       } 

      } 


     if ($record_id) { # handle last result 
      push @datasetarray, $tmphash; 
      $tmphash = {}; 
     } 
    } 
    close IN; 
} 

foreach my $row (@datasetarray) { 


    print $_, "\n";      #Time doesn't get printed 
    print "\t $row->{'peer_ip'}\n";  #OK 
    print "\t $row->{'peer_as'}\n";  #OK 
    print "\t $row->{'local_ip'}\n";  #OK 
    print "\t $row->{'local_as'}\n";  #OK 
    print "\t $row->{'next_hop'}\n";  #OK 
# print "\t $row->{'nodes_and_index'}\n"; # Are these guys ok ? since they are arrays 
# print "\t $row->{'withdraw_prefix'}\n"; # Are these guys ok ? since they are arrays 
# print "\t $row->{'announce_prefix'}\n"; # Are these guys ok ? since they are arrays 


} 

===================================================================================================================== ===================================================

ответ

1

Проще всего поместить ваш $recordcnt в самый ключ, как это $record_id = $recordcnt.'_'.$time[1]."_".$time[2]; и убедитесь, что он никогда не обнуляется внутри цикла (у вас есть строка, которая делает $ recordcnt = 0`, это неправильно). Также я не нашел места, где вы фактически увеличиваете recordcnt.


Однако, мне кажется, что вам будет намного лучше использовать массив хэшей вместо простого хэша. Массив будет упорядочен так же, как и ваш входной файл, но вы можете использовать sort, чтобы отсортировать его любым способом, и вы не будете перепутаны со странными счетчиками и т. Д. Слишком сложно переписать его с помощью массива.

Сначала создайте массив, в котором будут храниться все ваши данные в начале вашего скрипта (назовем его @myarray).

Прежде чем начать цикл, создайте хэш-ссылку ref (ссылка на хэш, которую можно обрабатывать), которая будет содержать один объект.

my $tmphash = {}; 
while (<IN>) {  
...... 

Теперь замените ваш $hash{$record_id}{$recordcnt} только с $tmphash->

(например,

if ($peer_ip) {$hash{$record_id}{$recordcnt}{'peer_ip'} = $peer_ip;}

теперь будет

if ($peer_ip) {$tmphash->{'peer_ip'} = $peer_ip;} и так далее)

Когда вы знаете, что вы собрали весь объект в tmphash, просто нажмите tmphash в массиве, переинициализировать tmphash и продолжить со следующего объекта.

push @myarray, $tmphash; 
$tmphash = {}; 

Все сделано! Теперь все, что вам нужно сделать, это цикл через массив для печати Ваших данных

foreach my $row (@myarray) { 
    print "\t $row->{'peer_ip'}\n"; 
    #... and so on 

РЕДАКТИРОВАНИЯ

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

#!/usr/bin/perl -w 

use strict; 
use warnings; 


my @datasetarray; 
my $Dir = "/root/updates/processed/"; 
my $exit = 0; 

opendir(DIRECTORY, $Dir) or die $!; 

while (my $file = readdir(DIRECTORY)) { 

    unless ($file=~/\.hr$/){next;} 
    #unless ($file=~/\.txt$/){next;} 

    my $file = $Dir."/".$file; 
    print "$file\n"; 

    open (IN, $file) or die "error reading file: ", $file,"\n"; 

    my $record_id = ""; 
    my $type = ""; 
    my $peer_ip = ""; 
    my $peer_as = ""; 
    my $local_ip = ""; 
    my $local_as = ""; 
    my $next_hop = ""; 
    my @nodes_and_index =(); 
    my @withdraw_prefix =(); 
    my @announce_prefix =(); 


    my $tmphash = {}; 

    while (<IN>) {   

     #$exit++; last if ($exit==5); 

     if (/^TIME/) { 


      if ($type) {$tmphash->{'type'} = $type;} 
      if ($peer_ip) {$tmphash->{'peer_ip'} = $peer_ip;} 
      if ($peer_as) {$tmphash->{'peer_as'} = $peer_as;} 
      if ($local_ip) {$tmphash->{'local_ip'} = $local_ip;} 
      if ($local_as) {$tmphash->{'local_as'} = $local_as;} 
      if ($next_hop) {$tmphash->{'next_hop'} = $next_hop;} 
      if (@nodes_and_index) {push @{$tmphash->{'nodes_and_index'}}, @nodes_and_index;} #~#~ 
      if (@withdraw_prefix) {push @{$tmphash->{'withdraw_prefix'}}, @withdraw_prefix;} #~#~ 
      if (@announce_prefix) {push @{$tmphash->{'announce_prefix'}}, @announce_prefix;} #~#~ 

      if ($record_id) { #~#~ 
       $tmphash->{'time'} = $record_id; #~#~ 
       push @datasetarray, $tmphash;#~#~ 
       $tmphash = {};#~#~ 
      } #~#~ 
#The three commented lines above provide error, thus i don't know if i am implementing it the right way, since they are array and different from the others. 

      $peer_as = ""; 
      $peer_ip = ""; 
      $type = ""; 
      $local_ip = ""; 
      $local_as = ""; 
      $next_hop = ""; 
      $record_id = ""; 
      @nodes_and_index =(); 
      @withdraw_prefix =(); 
      @announce_prefix =(); 


      my @time = split '\s', $_; 
      $record_id = $time[1]."_".$time[2]; 


     } elsif (/^TYPE/) { 
      my @type_tmp = split '\s', $_; 
      $type = $type_tmp[1]; 

     } elsif (/^FROM/) { 
      my @from_tmp = split '\s', $_; 
      $peer_ip = $from_tmp[1]; 
      $peer_as = $from_tmp[2]; 
      $peer_as =~ s/AS//; 

     } elsif (/^TO/) { 
      my @to_tmp = split '\s', $_; 
      $local_ip = $to_tmp[1]; 
      $local_as = $to_tmp[2]; 
      $local_as =~ s/AS//; 

     } elsif (/^ASPATH/) { 

      my @nodes_tmp = split '\s', $_; 
       shift @nodes_tmp;  
      my $index = 0; 

      foreach my $node (@nodes_tmp) { 
        $index++; 
      push @nodes_and_index, ($node , $index); 
      } 

     }elsif (/^NEXT_HOP/) { 

      my @next_hop_tmp = split '\s', $_; 
      $next_hop = $next_hop_tmp[1]; 

     }elsif (/^WITHDRAW/) { 
      while (<IN>) {  
        last if !/^ +/;  
        push @withdraw_prefix, $_ ;   

       } 


     }elsif (/^ANNOUNCE/) { 

       while (<IN>) {   
        last if !/^ +/;  
        push @announce_prefix, $_; 

       } 

      } 


     #if ($record_id) { # handle last result #~#~ 
     #  push @datasetarray, $tmphash;#~#~ 
     #  $tmphash = {};#~#~ 
     # }#~#~ 
    } 
    close IN; 

    #insert the last element of the file 
    if ($type) {$tmphash->{'type'} = $type;} #~#~ 
    if ($peer_ip) {$tmphash->{'peer_ip'} = $peer_ip;} #~#~ 
    if ($peer_as) {$tmphash->{'peer_as'} = $peer_as;} #~#~ 
    if ($local_ip) {$tmphash->{'local_ip'} = $local_ip;} #~#~ 
    if ($local_as) {$tmphash->{'local_as'} = $local_as;} #~#~ 
    if ($next_hop) {$tmphash->{'next_hop'} = $next_hop;} #~#~ 
    if (@nodes_and_index) {push @{$tmphash->{'nodes_and_index'}}, @nodes_and_index;} #~#~ 
    if (@withdraw_prefix) {push @{$tmphash->{'withdraw_prefix'}}, @withdraw_prefix;} #~#~ 
    if (@announce_prefix) {push @{$tmphash->{'announce_prefix'}}, @announce_prefix;} #~#~ 

    if ($record_id) { #~#~ 
     $tmphash->{'time'} = $record_id; #~#~ 
     push @datasetarray, $tmphash;#~#~ 
     $tmphash = {};#~#~ 
    } #~#~ 
} 

foreach my $row (@datasetarray) { 


    #print $_, "\n";      #Time doesn't get printed #~#~ 
    print "\t $row->{'time'}\n";  #~#~ 
    print "\t $row->{'peer_ip'}\n";  #OK 
    print "\t $row->{'peer_as'}\n";  #OK 
    print "\t $row->{'local_ip'}\n";  #OK 
    print "\t $row->{'local_as'}\n";  #OK 
    print "\t $row->{'next_hop'}\n";  #OK 
#you can print array refs like this, just make a check that they are declared 
    print "\t @{$row->{'nodes_and_index'}}\n" if ref $row->{'nodes_and_index'} eq 'ARRAY';#~#~ 
    print "\t @{$row->{'withdraw_prefix'}}\n" if ref $row->{'withdraw_prefix'} eq 'ARRAY';#~#~ 
    print "\t @{$row->{'withdraw_prefix'}}\n" if ref $row->{'withdraw_prefix'} eq 'ARRAY';#~#~ 


} 
+0

Благодарим вас за ответ и даю мне 2 варианта, которые я действительно ценю. Я хотел бы попробовать первый вариант, добавив recordcnt в record_id, как вы предложили. Пожалуйста, где я должен инициализировать и увеличивать его? Основываясь на результатах этого, я решит пойти с вариантом 2, который лучше, чем вы советовали :) –

+0

* Теперь у меня есть счетчик, который работает как ожидалось. Но я получаю дублированные значения, например: * ** ASPATH: 172193 1 19601 2 14835 3 4758 4 2379 5 172193 1 19601 2 14835 3 4758 4 2379 5 172193 1 19601 2 14835 3 4758 4 2379 5 ** * Результаты потому что это повторяется 3 раза, я не знаю почему. * –

+0

Поскольку вы используете этот 'if (/^TIME /) {' блок, чтобы отличать новые записи, вы должны увеличивать $ recordcnt внутри блока 'if'. Прямо сейчас вы устанавливаете его равным 0, если это неверно. Вы уже инициализируете его корректно за пределами всех циклов while. – foibs