如何确定字符串是否以哈希表的键开头?

时间:2015-05-27 12:46:37

标签: perl

如果子字符串以一组字符串中的一个开头,我需要检查大文件每行的特定子字符串。由于我还需要每个可能密钥的另一个属性,因此我目前在散列中表示搜索字符串和关联值:

my %nops = (   # Name and length of needed headers
                 'POS1'     => 308,
                 'POS2'     => 305,
                 'POSSBNOP' => 309,
                 'PERFORAT' => 10,
                 'DOCVV'    => 305,
                 'SPOOLING' => 308,
                 'DOCADR'   => 305,
                 'DOCFARBE' => 305,
                 'DOCMAIL'  => 305,
               );

搜索字符串的最大长度为8个字符,因此我从输入文件的每一行中提取子字符串。可能的子串的一些示例是我的测试数据:

my @nop = ( 'POS1 000', # matches 'POS1'
            'ABCDEF00', # no match (this would be the vast majority of lines in a file)
            'SPOOLING', # matches 'SPOOLING'
            'POS2 Rec', # matches 'POS2'
          );

我有一个可行的解决方案,它要求我迭代哈希的键以找到正确的条目(如果它存在):

for my $n (@nop) { # 
    while ( my ($key, $value) = each(%nops) ) {
        if ( $n =~ /^$key/ ) {
            print "NOP $key found, length $value\n";
            last;
        }
    }
}

我对解决方案不满意,因为它意味着对文件中的大多数行运行while循环的所有迭代。

我找到了另一个部分解决方案here,我喜欢它的简洁性,但它只告诉我哪些行匹配,而不是匹配的键,我需要弄清楚哈希值:

my $nop_keys = qr/${\ join('|', map quotemeta, keys %nops) }/;
for my $n (@nop) { # 
    print "String matched: $n\n" if $n =~ $nop_keys;
}

有没有更好的方法来解决这个问题? This question看起来很相关,但处理相反的情况:字符串与键匹配,而不是相反。也许不同的数据结构在这里会更有效率?

附带条件:我在Perl 5.10.0上,并且只能安装SUSE Linux Enterprise Server 11 SP2附带的任何其他软件包(不提供CPAN)。

3 个答案:

答案 0 :(得分:4)

你只需要捕捉匹配的内容。

my $pat = join '|', map quotemeta, keys %nops;
my $re = qr/$pat/;

for my $n (@nop) {
   my ($key) = $n =~ /^($re)/
      or next;

   my $val = $nops{$key};

   ...
}

答案 1 :(得分:1)

您可以通过从每行的开头捕获最多8个非空格字符并使用简单的哈希查找来更有效地处理此问题。

#!/usr/bin/env perl

use strict;
use warnings;

my %nops = (
    # Name and length of needed headers
    'POS1'     => 308,
    'POS2'     => 305,
    'POSSBNOP' => 309,
    'PERFORAT' => 10,
    'DOCVV'    => 305,
    'SPOOLING' => 308,
    'DOCADR'   => 305,
    'DOCFARBE' => 305,
    'DOCMAIL'  => 305,
);

while (my $line = <DATA>) {
    my ($key) = ($line =~ /\A ( \S{1,8} ) /x);
    next unless $key and exists( $nops{ $key } );
    print "$key => $nops{ $key }\n";
}

__DATA__
POS1 000 # matches 'POS1'
ABCDEF00 # no match (this would be the vast majority of lines in a file)
SPOOLING # matches 'SPOOLING'
POS2 Rec # matches 'POS2'

输出:

POS1 => 308
SPOOLING => 308
POS2 => 305

答案 2 :(得分:0)

拆分查询并将其用作哈希中的查找:

run_once

这假设密钥与空格的其余部分分开。