这个搜索在Perl中是如何工作的?

时间:2015-03-26 17:43:18

标签: perl

my ($len, $longest) =0;
length > $len and ($longest, $len)=($_, length) for @matches;

@matches存储一些子串。此代码捕获@matches中最长的子字符串,然后将其存储在$longest中。

源代码:

#!usr/bin/perl

use strict;
use Data::Dumper;

my $needle = "axibidm";
my $haystack = "axididm";
my @matches;


for my $start (0..length $needle) {
for my $len (1 .. ((length $needle)-$start)) {
    my $substr = substr($needle, $start, $len);
       push @matches, $haystack =~ m[($substr)]g;
    print "$substr\t";
    print "@matches\t\n";
  }
}

my ($len, $longest) = 0;

length > $len and ($longest, $len) = ($_, length) for @matches;


print "The longest common substring between\n", $needle, "\nand\n", $haystack, "\nis '$longest'\n";

3 个答案:

答案 0 :(得分:3)

有人太聪明了,或者他们打错了。或两者。可能两者都有。

有些事情正在发生,而这些代码并没有做它看起来正在做的事情。这不会将两个变量初始化为零。

my ($len, $longest) = 0;

这是一种欺骗性的写作方式。

my $len = 0;
my $longest;

for $matches是愚蠢的,只有一件事要迭代,为什么要使用循环呢?这个习惯用法偶尔用于将值放入$_并在各种默认构造中使用它,但这在这里用得不多。

接下来,以下是写do this if that的一种非常折磨的方式。它编写的方式使它成为一个单独的表达式,它将在for循环语句修饰符中起作用。

length > $len and ($longest, $len)=($_, length)

这样的写得好得多。

if( length > $len ) {
    $longest = $_;
    $len = length;
}

扩展它,并删除无用的for循环,我们得到......

my $len = 0;
my $longest;

if( length $match > $len ) {
    $longest = $match;
    $len = length $match;
}

另一个选项是$matches是一个数组引用,它们的意思是for @$matchesfor $matches仍然可以"工作"但它总是返回21的长度,因为数组引用字符串为ARRAY(0x7fc07c800468)

答案 1 :(得分:1)

这看起来几乎是故意混淆的。这是对同一逻辑的更详细的表达。

my $len = 0;
my $longest;

foreach my $match (@matches) {
  if (length($match) > $len) {
    $longest = $match;
    $len = length($match);
  }
}

所以让我们进行比较。

my ($len, $longest) = 0;

这声明了两个词法(my)变量$len$longest,并将第一个($len)设置为0,将$longest保留为其默认值为undef

这个结构:

 (code goes here) for @matches;

与此相同:

 for (@matches) {
     (code goes here)
 }

所以我们迭代@matches数组并为每个元素运行一次代码。在代码体内,特殊变量$_将保存当前元素。

length > $len and ($longest, $len) = ($_, length);

首先,(expression) and (code)是撰写if ( (expression) ) { (code) }的简写方式。它的工作原理是因为在Perl中,and以短路方式从左到右进行评估。也就是说,如果左侧表达式为假,则Perl不会对右侧进行评估,因为它的值无关紧要; false and任何内容都是false

如果在没有参数的情况下调用length,则表示length($_),这是正在检查的当前元素@matches的长度。

($var1, $var2) = ($val1, $val2)是并行分配,可将$var1设置为$val1,将$var2设置为$val2

答案 2 :(得分:1)

EXPR for LIST;

大致相同
for (LIST) { EXPR; }

EXPR1 and EXPR2;

大致相同
if (EXPR1) { EXPR2; }

(这不是普遍接受的做法,除非EXPR2是流量控制表达式(nextdie等)。)


length默认使用$_作为参数(length($_))。


( $x, $y ) = ( EXPR1, EXPR2 )

大致相同
$x = EXPR1;
$y = EXPR2;

(一个值得注意的区别是,您可以($x,$y)=($y,$x)交换值,但这里使用的是。)

(当两个标量赋值执行时使用列表赋值也不是普遍接受的做法。)


更常规的编写代码的方法是:

my $len = 0;
my $longest;
for (@matches) {
   if (length($_) > $len) {
      $longest = $_;
      $len = length($_);
   }
}