我有两个清单:
my @prefixes = ["abc", "def", "ghi", "jklmn"];
my @strings = ["abc123", "def456", "jklmnopqrst"];
我需要为每个字符串找到正确的前缀,以便“abc123”属于“abc”而“def456”属于“def”而“jklmnopqrst”属于“jklmn”。 所有字符串在@prefixes中都有一个前缀,但并非所有前缀都有匹配的字符串(请参阅“ghi”)。
我有这段代码:
use List::Util qw(first);
...
foreach my $str (@strings) {
my $prefix = first { $_ eq substr($str, 0, length($_)) } @prefixes;
print "$prefix\n";
# do something with $str and $prefix together
}
但它不起作用,我得到Use of uninitialized value $prefix in concatenation (.) or string
怎么了?
更新:所以这很容易解决。我应该使用()而不是[]来初始化我的列表。为了不关闭它,你将如何摆脱foreach
声明?
答案 0 :(得分:3)
您可以从前缀创建正则表达式模式,并使用它来构造哈希:
#!/usr/bin/env perl
use strict;
use warnings;
use YAML::XS;
my @prefixes = qw[abc def ghi jklmn];
my @strings = qw[abc123 def456 jklmnopqrst];
my ($prefix_re) = map qr/$_/, sprintf(
'^(?<prefix>%s)',
join '|', sort { length $b <=> length $a } @prefixes
);
print "$prefix_re\n";
my %matches = map { $_ =~ $prefix_re; ($+{prefix}, $_) } @strings;
print Dump \%matches;
输出:
abc: abc123 def: def456 jklmn: jklmnopqrst
如果多个字符串可以匹配前缀,则可以将前缀映射到匹配字符串列表:
#!/usr/bin/env perl
use strict;
use warnings;
use YAML::XS;
my @prefixes = qw[abc def ghi jklmn];
my @strings = qw[abc123 def456 def789 jklmnopqrst];
my ($prefix_re) = map qr/$_/, sprintf(
'^(?<prefix>%s)',
join '|', sort { length $b <=> length $a } @prefixes
);
print "$prefix_re\n";
my %matches;
for my $str ( @strings ) {
next unless $str =~ $prefix_re;
push @{ $matches{ $+{prefix} }}, $str;
}
print Dump \%matches;
输出:
--- abc: - abc123 def: - def456 - def789 jklmn: - jklmnopqrst
答案 1 :(得分:2)
但是,代替foreach
您可以使用map
,代码的可读性会大大降低。
#!/usr/bin/env perl
use strict;
use warnings;
use List::Util qw/ first /;
my @prefixes = ("abc", "def", "ghi", "jklmn");
my @strings = ("abc123", "def456", "jklmnopqrst");
# foreach my $str ( @strings ) {
# my $prefix = first { $_ eq substr( $str, 0, length( $_ )) } @prefixes;
# print $prefix, "\n";
# }
my @found = map { my $str = $_; first { $_ eq substr( $str, 0, length( $_ ))} @prefixes } @strings;
print join("\n", @found), "\n";