使用Perl从文本中提取多个Iterms

时间:2016-04-06 21:43:03

标签: perl

我需要从多行字符串中提取多个项目。

{
      'autoname' => 1,
      'class' => 'packetfilter',
      'data' => {
                  'action' => 'accept',
                  'auto' => 0,
                  'auto_type' => '',
                  'comment' => 'Allow access to Sandbox Server',
                  'destinations' => [
                                      'REF_NetworkAny'
                                    ],
                  'direction' => '',
                  'group' => 'SANDBOX',
                  'interface' => '',
                  'log' => 1,
                  'name' => 'TCP_5090 from SND (Network) to Any',
                  'services' => [
                                  'REF_SerTcpTcp5090',
                                  'REF_SerTcpTcp8200',
                                  'REF_SerTcpTcp8883',
                                  'REF_SerTcpTcpudp5090'
                                ],
                  'source_mac_addresses' => '',
                  'sources' => [
                                 'REF_MHTGIvpkvI'
                               ],
                  'status' => 1,
                  'time' => ''
                },
      'hidden' => 0,
      'lock' => '',
      'nodel' => '',
      'ref' => 'REF_PacPacTcp50FromSnd',
      'type' => 'packetfilter'
    }

我需要找到标签'服务',目的地和来源,并且只为每个标签提取REF标签。

示例:

services
REF_SerTcpTcp5090
REF_SerTcpTcp8200
REF_SerTcpTcp8883
REF_SerTcpTcpudp5090

destinations
REF_NetworkAny

sources
REF_MHTGIvpkvI

任何指导都将不胜感激。

3 个答案:

答案 0 :(得分:2)

这肯定看起来像Perl。您可以使用eval将其转换为Perl数据结构,但这会产生许多安全问题。

相反,使用the Safe module来评估它,但只允许某些运算符。这将阻止它执行某些不安全的操作,比如打开文件或添加函数。这是一个演示。

use v5.10;
use strict;
use warnings;

use Safe;

my $safe = Safe->new;
my $data = $safe->reval(join "", <DATA>) or die "reval failed: $@";
say join "\n", keys %$data;

__END__
{
      'autoname' => 1,
      'class' => 'packetfilter',
      'data' => {
                  'action' => 'accept',
                  'auto' => 0,
                  'auto_type' => '',
                  'comment' => 'Allow access to Sandbox Server',
                  'destinations' => [
                                      'REF_NetworkAny'
                                    ],
                  'direction' => '',
                  'group' => 'SANDBOX',
                  'interface' => '',
                  'log' => 1,
                  'name' => 'TCP_5090 from SND (Network) to Any',
                  'services' => [
                                  'REF_SerTcpTcp5090',
                                  'REF_SerTcpTcp8200',
                                  'REF_SerTcpTcp8883',
                                  'REF_SerTcpTcpudp5090'
                                ],
                  'source_mac_addresses' => '',
                  'sources' => [
                                 'REF_MHTGIvpkvI'
                               ],
                  'status' => 1,
                  'time' => ''
                },
      'hidden' => 0,
      'lock' => '',
      'nodel' => '',
      'ref' => 'REF_PacPacTcp50FromSnd',
      'type' => 'packetfilter'
}

安全不是100%安全,所以你不应该养成这个习惯。如果可能的话,使用可解析的格式(如JSON)进行数据序列化。

答案 1 :(得分:1)

如果您的输入数据集是有效的Perl代码,最简单的方法应该是使用eval评估代码,如其他答案所示。如前所述,如果您不信任输入数据的来源,则存在一些安全问题。因此,请仔细使用它并考虑使用模块来进一步缩小攻击面。 另一种解决方案可能是使用正则表达式。假设您在标量中包含完整的输入数据,则可以解析所需的项目

#!/usr/bin/env perl

use strict;
use warnings;

my $data = join "", <DATA>;

my @services = get_values(\$data, 'services');
my @destinations = get_values(\$data, 'destinations');
my @sources = get_values(\$data, 'sources');

print "Services: ", join(", ", @services),"\n";
print "Destinations: ", join(", ", @destinations),"\n";
print "Sources: ", join(", ", @sources),"\n";

sub get_values
{
    my ($inputdata, $key) = @_;

    # add quote signs around the key
    $key = "'$key'";

    if ($$inputdata =~ /$key => \[([^\]]+)\]/m)
    {
    # $1 contains the values
    my $values = $1;
    # remove empty lines, plus leading and tailing whitespaces
    $values =~ s/^\s*$|^\s+|\s+$//mg;
    # strip line breaks and single quotes
    $values =~ s/[\n']//g;
    # split into seperate fields
    my @result = split(/,/, $values);

    return @result;
    } else {
    return ();
    }
}

__END__
{
      'autoname' => 1,
      'class' => 'packetfilter',
      'data' => {
                  'action' => 'accept',
                  'auto' => 0,
                  'auto_type' => '',
                  'comment' => 'Allow access to Sandbox Server',
                  'destinations' => [
                                      'REF_NetworkAny'
                                    ],
                  'direction' => '',
                  'group' => 'SANDBOX',
                  'interface' => '',
                  'log' => 1,
                  'name' => 'TCP_5090 from SND (Network) to Any',
                  'services' => [
                                  'REF_SerTcpTcp5090',
                                  'REF_SerTcpTcp8200',
                                  'REF_SerTcpTcp8883',
                                  'REF_SerTcpTcpudp5090'
                                ],
                  'source_mac_addresses' => '',
                  'sources' => [
                                 'REF_MHTGIvpkvI'
                               ],
                  'status' => 1,
                  'time' => ''
                },
      'hidden' => 0,
      'lock' => '',
      'nodel' => '',
      'ref' => 'REF_PacPacTcp50FromSnd',
      'type' => 'packetfilter'
}

正则表达式方法的优点是不受信任的数据源没有(或至少减少)安全问题。

编辑:添加了示例代码。

答案 2 :(得分:-1)

作为已经注意到的评论者之一 - 数据是有效的perl - 可能由Data :: Dumper或类似的东西创建。要获取数据,只需评估它:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>



<a href="#section1">Section 1</a>

<!--For demo-->
<div class="spacer"></div>

<fieldset class="collapsed">
  <legend id="section1"><a href="#section1">Heading</a></legend>
  <div class="content">
    ..content XXXXX xxxxxxxxxxxnnnnnnnnnnnnn hbyigyugvyibrgh fwgewg wefgeh bbbbb uhuhouihoijpiok erhtru efwgwrhnj
  </div>
</fieldset>

请注意来自Data::Dumper documnetation;

的此警告

给定一个标量或引用变量列表,用perl语法写出它们的内容。引用也可以是对象。每个变量的内容在单个Perl语句中输出。正确处理自引用结构。

可以回避返回值以获取原始参考结构的相同副本。 (请考虑来自不受信任来源的eval和代码的安全隐患!)