В то время как и каждый раз смешанный цикл вопроса - PullRequest
2 голосов
/ 11 февраля 2010
!

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 A или test.pl B или ** test.pl Hello "

когда я передал два аргумента, он работает только некоторое время.

Успешно: Когда я запускаю 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 ]

3 голосов
/ 11 февраля 2010

Причина получения дублированного вывода в том, что регулярное выражение $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]; ... }), тогда проще и проще просто зацикливаться на массиве (for $elem (@arr) { ... }).

Ваш цикл foreach также можно заменить на оператор grep, но я оставлю это как упражнение для читателя.

3 голосов
/ 11 февраля 2010

Я не вижу проблемы, ваш скрипт обрабатывает __DATA__ и проверяет все входные слова по нему: так как "Hello" и "World" совпадают дважды каждое, он печатает 4 строки.

Если вы не хотите, чтобы он записывал несколько строк, просто добавьте last; после оператора print.

1 голос
/ 11 февраля 2010

Если вы хотите напечатать каждую строку из DATA только один раз, если один или несколько шаблонов совпадают, вы можете использовать grep. Обратите внимание, что использование \Q для цитирования метасимволов regex в аргументах командной строки и использование массива @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? Что должно произойти?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...