Perl中比较标量和数组(带正则表达式?)

3

我将简要说明,以免浪费您的时间:

简单的问题,我有一个数组,里面有数百只狗。

my @dogs = qw(Shepard Lab Dalmation Husky Chow Pitbull ...)

我希望你能将其与单只狗进行比较。

my $doggy = "Shepard";

我知道这很愚蠢,但我该怎么做呢?

(相关的IT技术内容需要根据具体情况进行翻译)
# Regex match against array?
# (This doesnt even work but its how i would think of doing it)
if ($doggy =~ /@dogs/) {
print $doggy;
}

提前感谢任何答案,我很感激你们帮助我解决这个可能非常愚蠢的问题。谢谢。


那么,你想“将它与一只单独的狗进行比较” - 那种比较不会一直返回false吗,因为它们是不相等的?还是说你想在狗的列表中查找你的狗的索引?你想验证你的狗是否被列出?请稍微具体一些。 - Nightfirecat
是的,就像你说的那样,在列表中找到我的狗的索引,这样我就可以看到牧羊犬是否在主狗列表中。 - user1058357
https://dev59.com/enRB5IYBdhLWcg3wF0HH https://dev59.com/p3I-5IYBdhLWcg3wVWli https://dev59.com/OXE95IYBdhLWcg3wRLwt http://stackoverflow.com/q/2678503 https://dev59.com/yXA85IYBdhLWcg3wJf4Z https://dev59.com/fE7Sa4cB1Zd3GeqP4pNk https://dev59.com/pnA75IYBdhLWcg3wkZ-A - daxim
7个回答

5
我会这样做:

我会这样做:

my %hDogs = map { $_ => 1 } @dogs;

if(exists($hDogs{$doggy})) { ... }

好的,将“主狗列表”转换为哈希表,并使用if-exists语句查看其是否在哈希表中,谢谢回答。我在想是否应该使用哈希表。 - user1058357
@user1058357,有超过10种方法可以做到这一点 :) - FailedDev
呵呵,如果我只能想到一个不起作用的东西,那肯定很糟糕 :P - user1058357
@user1058357 我们都经历过那个阶段。不要让它影响你。 - FailedDev

4
您可以使用grep命令:
my @dogs = qw(Shepard Lab Dalmation Husky Chow Pitbull);
my @wanted_dogs = grep {/^Shepard$/} @dogs;
print "@wanted_dogs\n";

结果:

Shepard

正则表达式可以根据需要进行更改,如果你只对第一个匹配的狗感兴趣,你可以在 $wanted_dogs[0] 中找到它。


谢谢,这个答案也很有帮助。 - user1058357
很高兴为您效劳。这正是grep的用途,而且它做得很好。 - flesk

3

智能匹配运算符

use warnings;
use strict;

my @dogs = qw(Shepard Lab Dalmation Husky Chow Pitbull);
my $doggy = "Shepard";
if ($doggy ~~ @dogs) {
    print $doggy;
}

2
假设您不是真的想要一个正则表达式匹配,只是想查看列表中是否有完全匹配项,则有多种选择。 智能匹配 是相对较新的、最简单和可能最快的方法。
经典的方法是 grepList::Util::first。如果您确实希望(例如)在 $dog 是 "Shep" 时匹配 "Shepard",您可以调整后两个使用正则表达式而不是eq
use strict;
use warnings;
use v5.10;

my @dogs = qw(Shepard Lab Dalmation Husky Chow Pitbull);
my $dog = "Shepard";
my $cat = "Ocicat";

say "Smart match";
say $dog ~~ @dogs;
say $cat ~~ @dogs;

say "Grep";
say grep { $_ eq $dog } @dogs;
say grep { $_ eq $cat } @dogs;

say "List::Util";
use List::Util qw/first/;
say first { $_ eq $dog } @dogs;
say first { $_ eq $cat } @dogs;

感谢您的输入,非常感谢任何建议。目前还不确定我将使用哪种方法。 - user1058357
除非你使用的是无法升级的过时 Perl(在这种情况下请使用 List::Util),否则请使用智能匹配。 - Quentin

1

有一些使用较新的智能匹配运算符的技术,但我更喜欢旧的经典方法:

my $dogs_re = join '|' => map quotemeta, @dogs;

if ($doggy =~ /$dogs_re/) {...}

这将创建一个正则表达式的交替,其中包含您狗的类型,并引用名称中的任何正则表达式特殊字符。

如果需要,您也可以编译正则表达式:

$_ = qr/$_/ for $dogs_re;  

这行代码应该放在定义 $dogs_re 的行之后,如果你将会多次使用正则表达式的话,可能会带来一些性能优势。


1
这有点难以理解,但我相信它是一个好的解决方案,我会再读几百遍的:P,谢谢你的回复。 - user1058357
啊,我明白了,这就相当于使用多个匹配选项的正则表达式:(Shepard|Husky|Chow),然后它可以执行一个正则表达式语句。这非常有用,因为我将会重复使用这个正则表达式数百次,并且需要对其进行编译以提高速度。非常感谢。 - user1058357
考虑使用一个模块来优化这样的正则表达式。Regexp::Assemble 是一个不错的选择。 - Zaid
@Zaid => 从5.9.2开始,Perl的正则表达式引擎将自动将像这样的链式替代项优化为trie。 - Eric Strom
我认为$dogs_re = qr/$dogs_re/更短且更易理解。 - Eugene Yarmash

0

试试这个,

$" = "|";
my @dogs=qw(Shepherd Lab Poodle Foo Bar);
my $temp = "@dogs";
my $dog = "Lab";
print "$1 found" if ($dog =~ /($temp)/);

0

对于最佳答案,我可能会选择哈希查找解决方案,但有许多方法可以做到这一点。这是其中之一。

请注意,这将我们的狗名用作正则表达式,并在列表上进行迭代,而不是相反。

use v5.10; # needed for say
@dogs=qw(Shepherd Lab Poodle Foo Bar); 
$dog = 'Lab'; 
/\Q$dog\E/i and say for @dogs;"

你可以控制匹配的严格程度: /\Q$dog\E/i 是最宽松的,忽略大小写,在单词中任何地方匹配。例如,“Lab”将与“Yellow Lab”,“Labrador”等匹配。 /^\Q$dog\E$/ 是最严格的,区分大小写,整个单词匹配。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接