Perl模块或方法来获取嵌套花括号内的数据?

时间:2017-06-06 20:48:43

标签: perl module nested curly-braces braces

我有一些配置文件(实际上是从防火墙报告中导出),使用这种结构:

 policies {
        apply-groups default-log;
        from-zone Trust to-zone DMZ {
            policy policy-66 {
                match {
                    source-address g_DMZ_SRV_;
                    destination-address g_DMZ_SRV;
                    application any;
                }
                then {
                    permit;
                }
            }
            policy policy-9 {
                match {
                    source-address g_h_OpenMail-Server;
                    destination-address g_in_DMZ_Exchange;
                    application t_1023;
                }
                then {
                    permit;
                }
            }
        }
        from-zone DMZ to-zone Blabla {
            policy policy-68 {
                match {
                    source-address g_DMZ_SRV_2_;
                    destination-address g_DMZ_SRV_3;
                    application T_22-ssh;
                }
                then {
                    permit;
                }
            }
            policy policy-95 {
                match {
                    source-address g_h_OpenMail-Server-2;
                    source-address 1.2.0.3;
                    destination-address g_in_DMZ_Exchange-1;
                    destination-address 10.25.32.64;
                    application t_1024;
                }
                then {
                    permit;
                }
            }
        }

}

并且我想在Perl中解析它,以便构建一个哈希,例如(或简单地设置条件来处理数据),我可以在之后利用它,例如:

Trust-to-DMZ
      policy-66
            source => g_DMZ_SRV
            destination => blabla
      policy-44
            source => source1
                      source2
                      source3
            destination => dest1
            ports => port1
DMZ-to-Trust
      policy-XX

我想知道:

  1. 如果你知道某些模块帮助完成这样的任务(我想我可以使用Text :: Balanced,我在其他一些帖子中找到了一些例子)

  2. 是否有一些方法/最佳做法可以避免肮脏的工作?

  3. 我想我可以“计算”大括号的数量并在循环中做循环..但它会很脏。

    是否有更简单的解决方案或模块自动执行此操作? (比如存在XML文件的模块,例如, XML ::简单将XML的内容放入哈希中,我会期望类似的东西?)

    否则我会开始编写脏东西并在此处发布我的进度

    谢谢!

    6月8日编辑,只是你知道,它适用于脏的脏脏代码(我不是开发人员,道歉),这不是我想要的,因为它是不适应..而且显然很脏 你被警告了! :)所以如果你不想要血液,请不要看它

    use warnings;
    use lib '/opt/csm/64-bit/cpan/5.16.3-2013.03/lib';
    use Data::Dumper;
    
    my ( $policies_flag, $fromzone_flag, $policy_flag, $match_flag, $zone_flag ) = ( 0,0,0,0,0 );
    my ( $details_flag, $clos_flag, $then_flag, $permit_flag, $clos2_flag, $final_flag ) = ( 0,0,0,0,0,0 );
    
    my $fromzone;
    my $tozone;
    
    my %pols;
    my $clos_counter;
    
    die "Usage: $0 <path_to_file>" if $ARGV[0] eq '';
    
    open D, '<', $ARGV[0] or die "cannot open $ARGV[0] for read\n";
    @data = <D>;
    close D;
    
    
    OUTER: foreach my $str (@data) {
    
         next if $str =~ /^$/;
         next if $str =~ /apply-groups/;
         chomp $str;
    
    if ( $str =~ /\s*policies\s+\{/ ) {
            $policies_flag = 1;
            next OUTER;
    }
    
    
    # policies
    if ($policies_flag == 1) {
    
        if ($str =~ /from-zone\s\S+\sto-zone\s\S+\s\{$/) {
            next if $str =~ /(<|>)/;
            ( $fromzone, $tozone ) = ( split(/\s+/,$str) )[2,4];
            $fromzone_flag = 1;
            next OUTER;
        }
    
        # from-zone
        if ($fromzone_flag == 1) {
    
            if ($str =~ /policy\s+\S+\s+\{/) {
                $policy_flag = 1;
                $clos_counter=0;
                ( $policy_name ) = ( split(/\s+/, $str) )[2];
                $pols{$policy_name}{from_zone} = "$fromzone";
                $pols{$policy_name}{to_zone} = "$tozone";
                next OUTER;
            }
    
            # pol
            if ($policy_flag == 1) {
    
                if ($str =~ /match\s+\{/) {
                    $match_flag = 1;
                    next OUTER;
                }
    
            }
    
            # match
            if ($match_flag == 1) {
    
                if ($str =~ /\S+\s+\S+;$/) {
                    $details_flag = 1;
    
                    if ($str =~ /source-address/) {
                        ( $sources ) = ( split(/\s+/, $str) )[2];
                        $sources =~ s/;//;
                        push( @{$pols{$policy_name}{sources}}, "$sources");
                    } elsif ($str =~ /destination-address/) {
                        ( $dests ) = ( split(/\s+/, $str) )[2];
                        $dests =~ s/;//;
                        push( @{$pols{$policy_name}{destinations}}, "$dests");
                    } elsif ($str =~ /application/) {
                        ( $ports ) = ( split(/\s+/, $str) )[2];
                        $ports =~ s/;//;
                        push( @{$pols{$policy_name}{ports}}, "$ports");
                    }
    
                    next OUTER;
                }
    
            }
    
            # rest
            if ($details_flag == 1) {
    
                if ($str =~ /\s*\}\s*$/) {
                    if ($clos_counter == 0) {
                        $clos_flag = 1;
                        $clos_counter++;
                        next OUTER;
                    }
                }
    
            }
    
            # then
            if ($clos_flag == 1) {
    
                if ($str =~ /\s*then\s+\{$/) {
                    $then_flag = 1;
                    next OUTER;
                }
    
            }
    
            # permit
            if ($then_flag == 1) {
    
                if ($str =~ /\s*permit;$/) {
                    $permit_flag = 1;
                    $pols{$policy_name}{action} = ( split(/\s+/,$str) )[1];
                    next OUTER;
                }
    
            }
    
            # clos2
            if ($permit_flag == 1) {
    
                if ($str =~ /\s*\}\s*$/) {
                    if ($clos_counter == 1) {
                        $clos2_flag = 1;
                        $clos_counter++;
                        next OUTER;
                    }
                }
    
            }
    
            # final close
            if ($clos2_flag == 1) {
    
                if ($str =~ /\s*\}\s*$/) {
                    if ($clos_counter == 2) {
                        $final_flag = 1;
                        $clos_counter++;
                        next OUTER;
                    }
                }
    
            }
    
            # ultimate zone
            if ($final_flag == 1) {
    
                if ($str =~ /\s*\}\s*$/) {
                    if ($clos_counter == 3) {
                        $zone_flag = 1;
                        $clos_counter++;
                        next OUTER;
                    }
                }
    
            }
    
            # ulti pols
            if ($zone_flag == 1) {
    
                if ($str =~ /\s*\}\s*$/) {
                    if ($clos_counter == 4) {
                        $clos_counter++;
                        last OUTER;
                    }
                }
    
            }
    
    
        }
    
    }
    
    }
    
    print Dumper(\%pols);
    

    给出:

    $VAR1 = {
          'policy-68' => {
                           'ports' => [
                                        'T_22-ssh'
                                      ],
                           'sources' => [
                                          'g_DMZ_SRV_2_'
                                        ],
                           'to_zone' => 'Blabla',
                           'from_zone' => 'DMZ',
                           'action' => 'permit;',
                           'destinations' => [
                                               'g_DMZ_SRV_3'
                                             ]
                         },
          'policy-9' => {
                          'ports' => [
                                       't_1023'
                                     ],
                          'sources' => [
                                         'g_h_OpenMail-Server'
                                       ],
                          'to_zone' => 'DMZ',
                          'from_zone' => 'Trust',
                          'action' => 'permit;',
                          'destinations' => [
                                              'g_in_DMZ_Exchange'
                                            ]
                        },
          'policy-66' => {
                           'ports' => [
                                        'any'
                                      ],
                           'sources' => [
                                          'g_DMZ_SRV_'
                                        ],
                           'to_zone' => 'DMZ',
                           'from_zone' => 'Trust',
                           'action' => 'permit;',
                           'destinations' => [
                                               'g_DMZ_SRV'
                                             ]
                         },
          'policy-95' => {
                           'ports' => [
                                        't_1024'
                                      ],
                           'sources' => [
                                          'g_h_OpenMail-Server-2',
                                          '1.2.0.3'
                                        ],
                           'to_zone' => 'Blabla',
                           'from_zone' => 'DMZ',
                           'action' => 'permit;',
                           'destinations' => [
                                               'g_in_DMZ_Exchange-1',
                                               '10.25.32.64'
                                             ]
                         }
        };
    

2 个答案:

答案 0 :(得分:1)

在我的或许不完全公正的意见中,Marpa::R2是解决问题类型的好方法。

答案 1 :(得分:1)

Marpa社区的Ron Savage提出了以下建议:


    my($parser) = Text::Balanced::Marpa -> new
    (
        open  => ['{'],
        close => ['}'],
    );

    my($text)   = read_text('policies.txt');
    my($result) = $parser -> parse(text => \$text);

    print "Parse result: $result (0 is success)\n";
    #print join("\n", @{$parser -> tree -> tree2string}), "\n";

    my($indent);

    for my $node ($parser -> tree -> traverse($parser -> tree -> POST_ORDER) )
    {
        $indent = '  ' x $node -> depth;
        $text   = ${$node -> meta}{text} =~ s/\n|[{}]//gr;

        say $indent, $text if ($text);
    }

Output:

    Parse result: 0 (0 is success)
  policies 
            apply-groups default-log;        from-zone Trust to-zone DMZ 
                  policy policy-66 
                        match 
                              source-address g_DMZ_SRV_;                    destination-address g_DMZ_SRV;                    application any;                
                        then 
                              permit;                

                  policy policy-9 
                        match 
                              source-address g_h_OpenMail-Server;                    destination-address g_in_DMZ_Exchange;                    application t_1023;                
                        then 
                              permit;                


            from-zone DMZ to-zone Blabla 
                  policy policy-68 
                        match 
                              source-address g_DMZ_SRV_2_;                    destination-address g_DMZ_SRV_3;                    application T_22-ssh;                
                        then 
                              permit;                

                  policy policy-95 
                        match 
                              source-address g_h_OpenMail-Server-2;                    source-address 1.2.0.3;                    destination-address g_in_DMZ_Exchange-1;                    destination-address 10.25.32.64;                    application t_1024;                
                        then 
                              permit;                

This gist包含上面的代码和输出。 Stackoverflow的格式化程序坚持要对所有内容进行缩进,无论它是否理解 - 可以依靠gist包含一个预先损坏的副本。