检查哈希表的键中是否存在字符串的一部分

时间:2019-04-17 14:56:03

标签: perl hash

我正在处理perl中的哈希表。

我有多个字符串,具有多个长度和多个-

pre1-pre2-text1-text2
pre3-text3
pre4-pre5-pre6-text4

我有一个带有以下键的%hash

pre1-pre2
pre3
pre4-pre5-pre6

因此,键%hash仅包含字符串的pre部分。

如何确定第一个字符串pre1-pre2-text1-text2%hash的键之间是否匹配?

3 个答案:

答案 0 :(得分:2)

一种方法:使用键交替形成模式,并针对该模式测试字符串

use warnings;
use strict;
use feature 'say';

my @strings = qw(pre-not pre1-pre2-text1-text2 pre3-text3 pre4-pre5-pre6-text4);

my %h = ( 'pre1-pre2' => 1, 'pre3' => 1, 'pre4-pre5-pre6' => 1 );

my $keys_re = join '|', map { quotemeta } keys %h; 

foreach my $str (@strings) { 
    say $str  if $str =~ /$keys_re/;
}

这具有二次复杂度,但是交替不会遍历所有键,而是C(正则表达式本身)。

可能的改进(或必要性!)可能是对键进行适当排序。例如,最短的优先

my $keys_re = join '|', map { quotemeta } sort { length $a <=> length $b } keys %h; 

如果某些键具有相同的部分,这可能会有所帮助,但请注意,这可能是一次不重要的调整,可能会影响正确性-并且可能需要 ;仔细考虑。

要获取密钥本身,请在模式周围添加捕获括号

foreach my $str (@strings) { 
    say "$str matched by key: $1"  if $str =~ /($keys_re)/;
}

其中$1包含与之匹配并被捕获的替代,这是关键。

答案 1 :(得分:1)

我在小Perl代码中添加了您提供的输入,并且可以检查按键是否匹配

#!/usr/bin/perl
use warnings;

my %langs = ( "pre1-pre2" => 'pre1-pre2',
 "pre3" => 'pre3',
 "pre4-pre5-pre6" => 'pre4-pre5-pre6');

@pats=("pre1-pre2-text1-text2", "pre3-text3", "pre4-pre5-pre6-text4");

for(keys %langs){
  foreach $ss (@pats){
    if (index($ss,$_) != -1){
      print("Key contains:",$_, "|", $ss,"\n");
    }
    else{
      print("NOT FOUND:",$_, "|", $ss,"\n");
    }
  }
}

注意:如果我正确地理解了您的要求,那么它将为您提供帮助。

答案 2 :(得分:1)

此答案假设pre不能出现在字符串的中间(即,您不会有pre1-pre2-text1-pre5这样的字符串,而前缀只会是pre1-pre2)。如果此假设无效,请使用/^((?:pre\d+)(?:-pre\d+)*)/代替/^(.*pre\d+)/(我更喜欢后者,因为它可读性更好,但前者更为精确)。

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

my %pre = map { $_ => 1 } qw(pre1-pre2 pre3 pre4-pre5-pre6);

while (<DATA>) {
    my ($prefix) = /^(.*pre\d+)/;
    if ($prefix && exists $pre{$prefix}) {
        say "Prefix exists: $prefix";
    } else {
        say "Prefix doesn't exist: $prefix";
    }
}

__DATA__
pre1-pre2-text1-text2
pre3-text3
pre4-pre5-pre6-text4
pre7-pre8-text5

如果您可以在行pre1-pre2-text1中使用前缀应该只是pre1,则此解决方案将不起作用。在这种情况下,除了迭代哈希的所有键并检查它们是否与字符串的开头匹配之外,您别无选择。

while (<DATA>) {
    for my $prefix (keys %pre) {
        if (/^\Q$prefix/) {
            say "Found prefix: $prefix";
            last;
        }
    }
}

但是,这要低得多,因为您需要遍历每一行的所有哈希键。
关于\Q:即使您的前缀包含特殊的正则表达式字符(例如+.),它也可以确保该解决方案有效。如果前缀始终像pre1-pre2一样,则可以省略\Q


如果您在理解my %pre = map { $_ => 1 } qw(pre1-pre2 pre3 pre4-pre5-pre6);时遇到困难:这是简明的版本

my %prev = (
    'pre1-pre2'      => 1,
    'pre3'           => 1,
    'pre4-pre5-pre6' => 1
);