【问题标题】:While and foreach mixed loop issuewhile 和 foreach 混合循环问题
【发布时间】:2010-02-12 00:36:45
【问题描述】:

!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 !

当我传递一个参数时,它运行良好。 比如我运行 test.pl Atest.pl B 或 **test.pl Hello"

当我传递两个参数时,它只工作一段时间。

成功:当我运行 test.pl A Btest.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>

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

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

【问题讨论】:

    标签: perl foreach


    【解决方案1】:

    我没有发现问题,您的脚本处理 __DATA__ 并针对它测试所有输入词:由于“Hello”和“World”各匹配两次,因此它打印 4 行。

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

    【讨论】:

    • 嗨,坎普。是的,正如你所说。但我不想打印重复的行。谢谢。
    • 然后在print 语句之后添加一个last;
    【解决方案2】:

    您得到重复输出的原因是因为正则表达式$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

    • 1234563 /p>

    您的foreach 循环也可以替换为grep 语句,但我将把它留给读者作为练习。

    【讨论】:

    • 嗨,戴夫,我发现了一个错误。如果我运行 test.pl World Hello,(swap Hello World to World Hello) 输出仍然错误。 :-)
    【解决方案3】:

    假设您只想在一个或多个模式匹配时从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 !
    

    以下是脚本中的一些 cmets,可帮助您学习:

    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;
    

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

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

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

    【讨论】:

    • 顺便说一句,当我将( 传递给我上面的程序时,产生并生成了一个错误Unmatched ( in regex; marked by &lt;-- HERE in m/( &lt;-- HERE / at D:\learning\perl\t .pl line 13, &lt;DATA&gt; line 1.,否则世界?效果很好。你上面的脚本修复了这个错误。
    • @Nano HE Rica ederim ;-) 主要问题是,如果__DATA__ 中没有字符串World?,您是否希望World? 匹配输入。它是匹配的,因为d? 意味着d 在模式中是可选的。在将$_ 插入qr 之前,在模式中使用\Q 意味着? 将被引用,现在? 必须按字面匹配。
    猜你喜欢
    • 1970-01-01
    • 2011-06-19
    • 1970-01-01
    • 2011-03-04
    • 1970-01-01
    • 1970-01-01
    • 2012-03-13
    • 2014-11-22
    • 1970-01-01
    相关资源
    最近更新 更多