0

找到第一个匹配项后我需要退出循环并转到循环中的另一个搜索

use strict;
use warnings;

my %iptv;
sub trim($) {
    my $string = shift;
    $string =~ s/\r\n//g;   
    $string =~ s/^\s+//;    
    $string =~ s/\s+$//;    
    return $string;

my @files=</tests/*>;
open IN, "/20131105.csv";
LINE: while (<IN>) {
        chomp;
         my @result = split(/;/,$_);
         my $result1 = trim($_);
         $result[1] = trim($result[1]);
         $iptv{$result[1]} = $result1;
    }
close IN;

foreach my $file (@files) {
        open FILE, "$file";
        while (<FILE>) {
                chomp;
                my ($mac, $date) = split(/;/,$_);               
                my @date1 = split(/\s/, $date);
                print "$iptv{$mac};$date1[0]\n" if defined $iptv{$mac};
                last LINE if (defined $iptv{$mac});
                }
close FILE;
}

我尝试使用“last”功能,但它找到了第一个匹配项并结束程序。我必须放在最后?

4

2 回答 2

1

让我们看一下文档:

$ perldoc -f last
last LABEL
last    The "last" command is like the "break" statement in C (as used
        in loops); it immediately exits the loop in question. If the
        LABEL is omitted, the command refers to the innermost enclosing
        loop. The "continue" block, if any, is not executed:

            LINE: while (<STDIN>) {
                last LINE if /^$/;  # exit when done with header
                #...
            }

        "last" cannot be used to exit a block that returns a value such
        as "eval {}", "sub {}" or "do {}", and should not be used to
        exit a grep() or map() operation.

        Note that a block by itself is semantically identical to a loop
        that executes once. Thus "last" can be used to effect an early
        exit out of such a block.

        See also "continue" for an illustration of how "last", "next",
        and "redo" work.

我们可以在这里清楚地阅读如何使用last. 如果一个标签被省略,它会跳出最里面的循环。因此,只有在我们不希望这样做的情况下,我们才使用标签。你想要这个,所以你不想要一个标签。

关于您的代码的一些注释:

检查 的返回值open,并使用三个带有词法文件句柄的参数。

open my $fh, "<", $file or die "Cannot open $file: $!";

这还有一个好处,即当词法变量$fh超出范围时,文件句柄将关闭。

当您拆分时,\s您会拆分一个空格。大多数情况下,这不是您想要的。例如,如果您有一个日期,例如

$str = "Jan  1 2013"    # (note the two consecutive spaces)

...这将拆分为列表"Jan", "", "1", "2013"(注意空字段)。只有当空字段相关时,这才是您想要的,例如类似 csv 的数据。split使用的默认行为' '(空格字符),其行为类似于/\s+/,除了它还去除前导空格。

请注意,此循环中的最后两个语句可以合并。@date1此外,不需要使用临时数组。这样你的代码看起来像:

open my $fh, "<", $file or die "Cannot open $file: $!";
while (<$fh>) {
    chomp;
    my ($mac, $date) = split /;/, $_;
    ($date) = split ' ', $date;
    if (defined $iptv{$mac}) {
        print "$iptv{$mac};$date\n" ;
        last;
    }
}
于 2013-11-08T12:21:41.190 回答
0
foreach my $file (@files) {
    open FILE, "$file";
    LINE: while (<FILE>) {
            chomp;
            my ($mac, $date) = split(/;/,$_);               
            my @date1 = split(/\s/, $date);
            print "$iptv{$mac};$date1[0]\n" if defined $iptv{$mac};
            last LINE if (defined $iptv{$mac});
            }
close FILE;
}

应该确保你只退出内循环。我想如果你完全去掉后面的 LINE 标签,它会同样有效,last但我建议总是使用标签,last以确保它不会做一些意想不到的事情,以防你添加一个额外的内部循环而忘记了last你希望在外面留下更远的循环的内部。

于 2013-11-08T09:40:19.320 回答