【问题标题】:checking the string against all values of multidimension hashmap in perl根据 perl 中多维哈希图的所有值检查字符串
【发布时间】:2013-12-04 13:34:10
【问题描述】:

我有以下要求

  • 读取示例数据文件/tmp/user_defined_connection.ini

MANAGEMENT=IDL||CIDL
NORTH=IDL,NORTHERN||VIDL,NORTH||IDL,NORTH
SOUTH=IDL,SOUTHERN||CIDL,SOUTH||IDL,SOUTH
  • 这里的每个 Key 都可以有多个这样的值,“,”表示 AND 操作,“||”表示是 OR 运算

  • 我需要根据另一个字符串 $instance 和每个值来检查它,所以我使用第一个键 MANAGEMENT 并获取它的值并检查 isnttance ....

$instance 包含 IDLCIDL

在下一次迭代中,将根据第二个键 NORTH 检查相同的实例,如果为 true,则函数应返回 NORTH,所以基本上我需要针对每个值逐一检查实例,然后返回我找到的键最后...下面是写到现在的代码

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

my @providerCloudSequence;
my %idlcodes;
open(my $iniFH, '<', '/tmp/user_defined_connection.ini') 
    or die "Unable to open file:$!\n";

while(<$iniFH>) {
    chomp;
    my @providerCloudClass = split('=',$_);
    push @providerCloudSequence, $providerCloudClass[0];
    if ($@) {
        print "Script Failed to get the Sequence....Exiting the Script\n";
        exit 1;
    }

    #my %idlcodes = map { split /=|\s+/; } <$iniFH>;
    my ($k, @r) = split /=|\Q||/;
    $idlcodes{$k} = [ map [ split /,/ ], @r ];
}
if($@){
        print "Script Failed to create the hash....Exiting the Script\n";
        exit 1;
 }
close $iniFH;
print Dumper \%idlcodes;
        my @interfaceSampleAliases = { "AFGHD_NORTH", 
                                           "NORTHERN_IIDID_IPV123", 
                                           "IDL_SOUTH", 
                                           "IDL_SOUTH_IUID", 
                                           "SOUTHERN_IND_IPV" };
        foreach (@interfaceSampleAliases){
            my $correctKey = getCorrectKey($_, %idlcodes, @providerCloudSequence)
            print $correctKey;
        }

}
# Providercloudsequence helps to maintain the precedence of the input file
# idlcodes is the hasp map where key is the key from file and value is an arracy of arrays ...see below the output of same

sub getCorrectKey($$$){
        my $interfaceAlias = $_[0];
        foreach ($_[2]) {
    # This is where I need the help , I want to get the value from 
    # hash %idlcodes using the key from @providerCloudSequence
    # The value of %idlcodes is kind of multiple Arrays where I want to 
    # grep $interfaceAlias against each with a AND in between elements 
    # and OR in between arrays , if true this is match
        }
}

##Data Dumper 输出:哈希看起来像

'NORTH_IPV' => [
                           [
                             'IDL',
                             'NORTHERN'
                           ],
                           [
                             'VIDL',
                             'NORTH'
                           ],
                           [
                             'IDL',
                             'NORTH'
                           ]
                         ],
          'MANAGEMENT' => [
                            [
                              'IDL'
                            ],
                            [
                              'CIDL'
                            ]
                          ],
          'SOUTH_IPV' => [
                           [
                             'IDL',
                             'SOUTHERN'
                           ],
                           [
                             'CIDL',
                             'SOUTH'
                           ],
                           [
                             'IDL',
                             'SOUTH'
                           ]
                         ]
预期产出
InterfaceAlias         correctKey

 "AFGHD_NORTH"           Doesnt Match anything so return NULL
 "NORTHERN_IIDID_IPV123" Doesnt Match anything so return NULL
 "IDL_SOUTH",            SOUTH_IPV
 "IDL_SOUTH_IUID",       SOUTH_IPV
 "SOUTHERN_IND_IPV"      Doesnt Match anything so return NULL
 "IDL_NORTH_IPV"         NORTH_IPV
 "IDL_ABDGJF"            MANAGEMENT

在这个例子中检查应该如何工作

检查 InterfaceAlias 是否包含 (IDL OR CIDL) ,然后检查相同的 interfaceAlias 是否包含 [(IDL AND NORTH) OR (VIDL AND NORTH) OR (IDL AND NORTHERN) ,然后检查相同的 interfaceAlias 是否包含 [(IDL AND SOUTH)或(CIDL 和南部)或(IDL 和南部)]

所以我们必须检查哈希 %idlcodes 中的所有值并返回匹配为 TRUE 的最后一个键

序列由数组@providerCloudSequence管理

单词的相邻并不重要 例如 SOUTH_XXX_CIDL 甚至“SOUTH IDL IPV WITH SPACES”应该匹配 SOUTH_IPV....这些只是示例,它基本上是一个包含匹配....虽然文件的结构是固定的。 ..(数据可能会有所不同)

【问题讨论】:

  • 您需要更好、更准确的“getCorrectKey”子输入和预期返回值的详细信息。很难理解你真正想要做什么!希望这会有所帮助
  • @Vorsprung 我已经添加了示例输入和输出
  • @mpapec ....建议的新帖子
  • 你的例子正确吗?根据您的 ini 文件,SOUTH 对应于IDL,SOUTHERNCIDL,SOUTH 而不是IDL,SOUTH。另外,SOUTH_XXX_CIDL 之类的内容会匹配任何内容,还是单词的顺序和相邻性很重要?
  • @Borodin 没有一个例子是正确的,看最后一个值 SOUTH_IPV 确实有一个值 IDL,SOUTH ....单词的相邻性并不重要是的 SOUTH_XXX_CIDL 甚至“SOUTH IDL IPV WITH SPACES”应该匹配SOUTH_IPV....这些只是示例,它基本上是一个包含匹配....虽然文件的结构是固定的...(数据可能会有所不同)

标签: perl hashmap hashtable


【解决方案1】:

我想我会从 ini 文件中构建一个正则表达式表,然后简单地逐个比较字符串。

我建议的代码如下。 get_correct_key 现在将所有下划线转换为连字符并剔除所有垃圾,例如,SOUTH-GWS-F-IDL100555236-Primary-1Gb 转换为 SOUTH-GWS-F-IDL-Primary-Gb。这也让我大大简化了正则表达式。

关于您的代码的一些注释

  • 优于use warnings,而不是在shebang行中添加-w

  • 标识符中的大写字母通常保留给包等全局变量,任何熟悉 Perl 的人都会感谢您在简单变量和子例程中使用小写和下划线

  • $@ 仅在一段 Perl 代码编译失败或调用 die 时设置。它只被eval 捕获,如果您不使用它,那么您在$@ 上的测试将始终失败

  • 您应该永远在 Perl 子例程定义中使用原型。它们与其他语言的原型不同,不会按照你的想法去做

希望对你有帮助

use strict;
use warnings;

open my $ini, '<', 'user_defined_connection.ini' or die $!;

my @provider_patterns;

while (<$ini>) {
  next unless /\S/;
  chomp;

  my ($key, $data) = split /=/, $_, 2;
  my $regex = join " |\n", map {
    join ' ', map { "(?=.* \\b $_ \\b )" } split /,/;
  } split /\|\|/, $data;

  push @provider_patterns, [ qr/$regex/xi, $key ];
}

my @aliases = (
  'AFGHD_NORTH',
  'NORTHERN_IIDID_IPV123',
  'IDL_SOUTH',
  'IDL_SOUTH_IUID',
  'SOUTHERN_IND_IPV',
  'IDL_NORTH_IPV',
  'IDL_ABDGJF',
  'IDL SOUTH',
  'MANAGEMENT_IPV_IDL100595208',
  'SOUTH-GWS-F-IDL100555236-Primary-1Gb',
);

for my $alias (@aliases) {
  my $found = get_correct_key($alias, \@provider_patterns);
  printf qq{ %-38s %-s\n}, qq{"$alias"}, defined $found ? $found : "Doesn't match anything so return undef";
}

sub get_correct_key {
  my ($alias, $patterns) = @_;
  $alias =~ tr/_/-/;
  $alias = join '-', $alias =~ /[a-z]+/gi;
  my $found;
  for my $pair (@$patterns) {
    my ($re, $key) = @$pair;
    $found = $key if $alias =~ $re;
  }
  $found;
}

输出

 "AFGHD_NORTH"                          Doesn't match anything so return undef
 "NORTHERN_IIDID_IPV123"                Doesn't match anything so return undef
 "IDL_SOUTH"                            SOUTH_IPV
 "IDL_SOUTH_IUID"                       SOUTH_IPV
 "SOUTHERN_IND_IPV"                     Doesn't match anything so return undef
 "IDL_NORTH_IPV"                        NORTH_IPV
 "IDL_ABDGJF"                           MANAGEMENT
 "IDL SOUTH"                            SOUTH_IPV
 "MANAGEMENT_IPV_IDL100595208"          MANAGEMENT
 "SOUTH-GWS-F-IDL100555236-Primary-1Gb" SOUTH_IPV

【讨论】:

  • 我添加了更多输入,例如“IDL SOUTH”.....它将其视为两个差异词,输出为"IDL" MANAGEMENT "SOUTH" Doesn't match anything so return undef MANAGEMENT_IPV_IDL100595208 ....这也失败了...可以我们请说一个单词以字母开头并以字母结尾
  • 第一个失败是因为我使用了qw 来填充数组@aliases。你所有的词都是按字母顺序排列的,即没有数字吗?那会让事情变得更简单。其实都是大写字母吗?
  • 我现在不在键盘附近,所以目前无法修复它。
  • 上面的例子中可以有数字后跟单词....另一个很好的例子是SOUTH-GWS-F-IDL100555236-Primary-1Gb这应该去SOUTH_IPV........@Borodin没问题每当你得到一分钟..
  • 我指的是 criteria 中的所有单词。您是否需要检查1GbIDL123A
猜你喜欢
  • 2016-02-22
  • 2012-09-06
  • 1970-01-01
  • 2019-08-08
  • 2014-06-18
  • 1970-01-01
  • 2020-07-19
  • 2015-01-17
  • 1970-01-01
相关资源
最近更新 更多