Perl регулярное выражение в хэш - PullRequest
4 голосов
/ 29 марта 2012

Я успешно анализирую конфигурационный файл cisco и извлекаю разделы конфигурации между каждым маркером (cisco использует символ!) С помощью многострочного регулярного выражения:

/(search string)/i .. /^!/ 

Мой код выглядит так:

#!/usr/bin/perl -w
use strict;
use Data::Dumper;

my (@results, @data) ;

#Test data to simulate a while loop on a file-handle running through a config file.
@data =  (
    "vlan 81" ,
    " name Vlan 81 test1" ,
    "!" ,
    "vlan 82" ,
    " name Vlan 82 test2" ,
    "!" ,
    "vlan 83" ,
    " name Vlan 83 test3" ,
    "!"
);

foreach ( @data ) {
    if ( /vlan/i .. /^!/ ) {
         push  (@results , $_) ;                
    }
}

print Dumper ( @results ) . "\n" ;

exit;

Это работает очень хорошо, но я хочу поместить результаты в хеш, где каждый раздел кода является анонимным массивом, поэтому результаты будут выглядеть примерно так:

%Vlan -> [Vlan 81, name Vlan 81 test1] , [Vlan 82, name Vlan 82 test2] , [Vlan 83, name Vlan 83 test3]

Но я не могу понять, как это сделать, мой код соответствует каждой строке между строкой поиска и маркером, и я просто перестраиваю результаты в другой массив, строка за строкой.

Любая помощь очень ценится.

Приветствия

Andy

Ответы [ 3 ]

4 голосов
/ 29 марта 2012

Я не уверен, что вы имеете в виду под хэшем, поскольку описываемое вами содержимое представляет собой просто список анонимных массивов. Здесь нет ключей, поэтому вы можете создать только массив. Если вы можете объяснить, какая часть данных должна быть ключом, мы можем использовать хеш.

Прагма use warnings предпочтительнее модификатора -w shebang, так как она более гибкая и может быть отменена.

Оператор диапазона .. может быть симпатичным, но вы не должны использовать его везде, где это возможно.

Установка входного разделителя на "!\n" позволит вам читать сразу по всем связанным строкам, которые затем могут быть помещены в ваш массив.

код выглядит так

use strict;
use warnings;

use Data::Dumper;

my @Vlan;

$/ = "!\n";

while  (<DATA>) {
  chomp;
  push @Vlan, [split /[\r\n]+/];
}

print Data::Dumper->Dump([\@Vlan], ['*Vlan']);

__DATA__
vlan 81
name Vlan 81 test1
!
vlan 82
name Vlan 82 test2
!
vlan 83
name Vlan 83 test3
!

выход

@Vlan = (
          [
            'vlan 81',
            'name Vlan 81 test1'
          ],
          [
            'vlan 82',
            'name Vlan 82 test2'
          ],
          [
            'vlan 83',
            'name Vlan 83 test3'
          ]
        );

EDIT

Если ключ хеша всегда является первой строкой набора записей, то эта программа создает хеш по вашему запросу

use strict;
use warnings;

use Data::Dumper;

my %Vlan;

$/ = "!\n";

while  (<DATA>) {
  chomp;
  my ($k, $v) = split /[\r\n]+/;
  $Vlan{$k} = $v;
}

print Data::Dumper->Dump([\%Vlan], ['*Vlan']);

__DATA__
vlan 81
name Vlan 81 test1
!
vlan 82
name Vlan 82 test2
!
vlan 83
name Vlan 83 test3
!

выход

%Vlan = (
          'vlan 81' => 'name Vlan 81 test1',
          'vlan 83' => 'name Vlan 83 test3',
          'vlan 82' => 'name Vlan 82 test2'
        );
3 голосов
/ 29 марта 2012

Измените конец вашей программы на

my %Vlan;

for (@data) {
  if (my $inside = /vlan/i .. /^!/) {
    if ($inside =~ /E0$/) {
      s/^\s+//, s/\s+$// for @results;  # trim whitespace
      $Vlan{ $results[0] } = join ", ", @results;
      @results = ();
    }
    else {
      push @results, $_;
    }
  }
}

print Dumper \%Vlan;

Оператор диапазона .. возвращает значение, которое заканчивается на "E0", когда правое условие истинно, поэтомумы можем использовать его в качестве подсказки, когда нужно помещать новую запись в %Vlan.

Возвращаемое значение - либо пустая строка для false, либо порядковый номер (начиная с 1) для true,Порядковый номер сбрасывается для каждого обнаруженного диапазона.К последнему порядковому номеру в диапазоне добавлена ​​строка "E0", которая не влияет на его числовое значение, но дает вам что-то для поиска, если вы хотите исключить конечную точку.

Ваша конечная цель не ясна, но кажется, что вы хотите, чтобы значения хеша были строками, а не массивами.Perl join создает строку, вставляя некоторый разделитель между элементами из списка значений.Приведенный выше код удаляет начальные и конечные пробелы из каждого значения в @results перед их использованием для заполнения %Vlan.

Вывод:

$VAR1 = {
          'vlan 81' => 'vlan 81, name Vlan 81 test1',
          'vlan 83' => 'vlan 83, name Vlan 83 test3',
          'vlan 82' => 'vlan 82, name Vlan 82 test2'
        };
2 голосов
/ 29 марта 2012

Этот сохраняет состояние вместо многострочного:

my %Vlan;

#Test data to simulate a while loop on a file-handle running through a config file.
@data =  (
    "vlan 81" ,
    " name Vlan 81 test1" ,
    "!" ,
    "vlan 82" ,
    " name Vlan 82 test2" ,
    "!" ,
    "vlan 83" ,
    " name Vlan 83 test3" ,
    "!"
);

foreach ( @data ) {
    if (/ name (\w+ \d+) /) {
      my $name = lc $1;
      die("undef $name") if (not defined $Vlan{$name});
      $Vlan{$name} = [$name, $_];
    } elsif ( /^(\w+ \d+)$/ ) {
      my $name = lc $1;
      $Vlan{$name}++;
    }
}

print Dumper ( %Vlan ) . "\n" ;

exit;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...