2012-03-29 49 views
4

我成功地解析思科配置文件,并抓住每一个标记之间配置的部分(Cisco使用符号!)使用的多行正则表达式:Perl的正则表达式多行匹配到散列

/(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] 

但我不能解决如何做到这一点,我的代码匹配搜索字符串和标记之间的每行,我最终将结果重建为另一个数组,逐行。

任何帮助,非常感谢。

干杯,

安迪

+0

你的目标不是那么清楚,因为你的例子已经有一个默认的键'Vlan'一个条目。对于这个键你有一个数组列表。你是不是指每个键(例如Vlan 81)都有散列值? – Matteo 2012-03-29 11:26:22

+0

是的,你说得对,谢谢你的评论,我会尽力在未来更加清晰。 – user1039417 2012-03-29 19:55:08

回答

4

我不知道你的意思的哈希什么,因为你的内容描述只是一个匿名数组列表。没有键,所以你只能生成一个数组。如果你可以解释哪部分数据是关键,那么我们可以去做一个哈希。

use warnings附注优于0123bshebang修饰符,因为它更灵活,可以否定。

范围运算符..可能是可爱的,但你不能在任何可能的地方使用它。

将输入分隔符设置为"!\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' 
      ] 
     ); 

编辑

如果哈希的关键是始终记录的第一线设置,然后这个程序产生,你要求

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' 
     ); 
+0

这正是我想要达到的目标,我会尝试一下。也没有意识到有多少特殊变量存在。谢谢您的帮助。 – user1039417 2012-03-30 08:54:08

2

这一个保持状态的,而不是做多行:

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; 
3

变更程序的结束

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; 

.. range operator回报与"E0"权当结尾的值的哈希手状态为真,所以我们可以使用它作为何时将新条目放入的提示。

返回的值是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' 
     };
+0

对E0感兴趣,我已经忘记了这种行为。我也会测试你的代码。 – user1039417 2012-03-30 08:58:23