同时和foreach混合循环问题

时间:2010-02-11 08:47:49

标签: perl foreach

C:!\ Perl的\ BIN \ perl.exe所在

use strict;
use warnings;


my $numArgs = $#ARGV + 1;
print "thanks, you gave me $numArgs command-line arguments.\n";



while (my $line = <DATA> ) { 
    foreach my $argnum (0 .. $#ARGV) {
        if ($line =~ /$ARGV[$argnum]/)
            {
                print $line;
            }
    }
} 

__DATA__ 
A
B
Hello World :-)
Hello World !
当我通过一个arg时,效果很好。 比如我运行 test.pl A test.pl B 或** test.pl Hello“

当我通过两个args时,它只运行一段时间。

成功:当我运行 test.pl A B test.pl A Hello 或** test.pl B Hello“

失败:当我运行 test.pl Hello World *

制作并输出重复的行:

D:\learning\perl>t.pl Hello World
thanks, you gave me 2 command-line arguments.
Hello World :-)
Hello World :-)
Hello World !
Hello World !

D:\learning\perl>

如何解决?感谢您阅读和回复。

[更新] 我不想打印重复的行。

3 个答案:

答案 0 :(得分:3)

我没有看到问题,你的脚本处理__DATA__并测试所有输入字:由于“Hello”和“World”每次匹配两次,它会打印4行。

如果您不希望它写多行,只需在last;语句后添加print

答案 1 :(得分:3)

您获得重复输出的原因是因为正则表达式$line =~ /Hello/匹配“Hello World”行,$line =~ /World/也匹配“Hello World”行。为防止这种情况发生,您需要添加一些内容以记住__DATA__部分中的哪些行已经打印过,这样如果它们与另一个参数匹配,您可以跳过它们。

另外,一些非常轻微的风格清理:

#!C:\Perl\bin\perl.exe
use strict;
use warnings;

my $numArgs = @ARGV;
print "thanks, you gave me $numArgs command-line arguments.\n";

while (my $line = <DATA> ) { 
    foreach my $arg (@ARGV) {
        if ($line =~ /$arg/)
            {
                print $line;
            }
    }
} 

__DATA__ 
A
B
Hello World :-)
Hello World !
  • 在标量上下文中使用数组会返回其大小,因此$size = @arr优先于$size = $#arr + 1

  • 如果您不打算使用计数器进行索引而不是通过数组(for $i (0..$#arr) { $elem = $arr[$i]; ... })进行索引,那么只需循环遍历数组就更简单,更简单({{1} })。

您的for $elem (@arr) { ... }循环也可以替换为foreach语句,但我会将其作为练习留给读者。

答案 2 :(得分:1)

假设您只想在一个或多个模式匹配时从DATA打印每一行,您可以使用grep。请注意,使用\Q在命令行参数中引用正则表达式元字符,并使用@patterns数组预编译模式。

大声朗读if grep { $line =~ $_ } @patterns如果$line匹配一个或多个模式; - )

#!/usr/bin/perl

use strict; use warnings;

printf "Thanks, you gave me %d command line arguments.\n", scalar @ARGV;

my @patterns = map { qr/\Q$_/ } @ARGV;

while ( my $line = <DATA> ) {
    print $line if grep { $line =~ $_ } @patterns;
}

__DATA__
A
B
Hello World :-)
Hello World !

以下是有关您的脚本的一些评论,可以帮助您了解:

my $numArgs = $#ARGV + 1;
print "thanks, you gave me $numArgs command-line arguments.\n";

命令行参数位于@ARGV(请阅读文档)。在标量上下文中,@ARGV计算该数组中元素的数量。因此,您只需使用:

printf "Thanks, you gave me %d command line arguments.\n", scalar @ARGV;

此外,您可以直接遍历@ARGV循环中foreach的元素,而不是索引访问。

while (my $line = <DATA> ) { 
    foreach my $arg ( @ARGV ) {
        if ( $line =~ /$arg/ ) {
            print $line;
        }
    }
} 

现在,如果我在命令行上将(传递给你的程序会怎么样?或者,即使World?会发生什么?