2016-06-12 2 views
1

я получил файл с именем numbers.txt, которая в основном линии с 5 цифр: они выглядят следующим образом:Проблема с вложенным циклом

1 2 3 4 5 

То, что я пытаюсь добиться, я хочу, чтобы прочитать эти цифры из линия (которая уже работает), то в каждой итерации я хочу, чтобы добавить +1 к каждому номеру, который был зачитан из этого файла и распечатать их на экране с печатью, так что конечный результат должен выглядеть следующим образом:

1 2 3 4 5 
2 3 4 5 6 
3 4 5 6 7 
4 5 6 7 8 
5 6 7 8 9 

,

#!/usr/bin/perl 

use strict; 
use warnings; 

open("handle", 'numbers.txt') or die('unable to open numbers file\n'); 
$/ = ' '; 

OUT: for my $line (<handle>) { 
     for (my $a = 0; $a < 5; $a++) { 
      chomp $line; 
      $line += 1; 
      print "$line "; 
       next OUT; 
     } 
} 
close("handle"); 

Не сделано зацикливание в Perl на некоторое время теперь, и было бы здорово, если бы кто-то может дать рабочий пример.

Кроме того, было бы здорово, если бы вы могли предоставить более одного рабочего пример, просто чтобы быть на будущее;) Спасибо

+0

Пожалуйста, смотрите [ 'Что я должен делать, если кто-то ответит на мой вопрос?'] (Http://stackoverflow.com/help/someone-answers) Маркировка ответы (как вы видите он подходит) важно для того, как работает этот сайт, для пользователей, которые ищут позже. – zdim

ответ

1

Вы можете попробовать это для размера.

#!/usr/bin/perl 

use strict; 
use warnings; 

open("handle", 'numbers.txt') or die('unable to open numbers file\n'); 

for my $line (<handle>) { 
    chomp $line; 
    for my $number (split /\s+/, $line) { 
     for (my $a = $number; $a < $number+5; $a++) { 
      print "$a "; 
     }  
     print "\n"; 
    } 
} 
close("handle"); 

Вы можете обойтись без $/=» ' и вместо того, чтобы позволить внешнюю итерацию цикла в строках файла.
Для каждой строки, которую вы хотите перебирать для каждого номера, которое разделяется пробелом, таким образом, split/\ s + /, $ line, который дает вам список чисел для внутреннего цикла. Для вашего вывода $ a начинается с числа, считанного из файла.

+0

'split/\ s + /' почти всегда будет 'split '' ' – Borodin

1

Это будет делать то, что вы после:

use strict; 
use warnings; 

while(<DATA>) { 
    chomp; 
    print "$_\n"; 
    my @split = split; 
    my $count = 0; 
    for (1..4){ 
     $count++; 
     foreach (@split){ 
      my $num = $_ + $count; 
      print "$num "; 
     } 
     print "\n"; 
    } 

} 

__DATA__ 
1 2 3 4 5 
1

Update   Добавлен еще один способ, это один в соответствии с посланной подходом.


Приращение каждого номера в строке, изменение строки на месте. Повтори это. Ниже приведены два способа сделать это. Еще один метод читает отдельные числа и печатает после целых последовательностей.

(1) С регулярными выражениями. Он также подходит в одном слое

echo "1 2 3 4 5" | perl -e '$v = <>; for (1..5) { print $v; $v =~ s/(\d+)/$1+1/eg; }' 

Это печатает желаемый результат. Но лучше положить его в сценарий

use warnings; 
use strict; 

my $file = 'numbers.txt'; 
open my $fh, '<', $file or die "can't open $file: $!"; 

while (my $line = <$fh>) { 
    # Add chomp($line) if needed for some other processing. 
    for (1..5) { 
     print $line; 
     $line =~ s/(\d+)/$1+1/eg; 
    } 
} 

/e Модификатор имеет решающее значение для этого. Он заставляет заменяющую сторону регулярного выражения оцениваться как код, а не как строку с двумя кавычками. Таким образом, вы можете фактически выполнить код там, и здесь мы добавим к захваченному номеру, $1+1, для каждого совпадающего числа, поскольку /g перемещается по строке. Это изменяет строку, поэтому следующая итерация for (1..5) увеличивает и т. Д. Я сопоставляю несколько цифр, \d+, что не обязательно в вашем примере, но имеет более общий смысл.

(2) Via split + map + join, неоднократно меняя линию в месте

while (my $line = <$fh>) { 
    for (1..5) { 
     print $line; 
     $line = join ' ', map { $_+1 } split '\s+', $line;    
    } 
} 

split получает список номеров из $line и подает его на map, которая увеличивает каждый, подавая свой вывод список - join. Объединенная строка присваивается обратно $line, и это повторяется. Я разделил на \s+, чтобы разрешить несколько пробелов, но это делает его очень «расслабленным» в том, какой формат ввода он принимает, см. perlrecharclass. Если вы знаете, что это одно место, пожалуйста, измените это на ' '.

(3) Возьмите число за раз и напечатайте целую последовательность, начиная с нее.

open my $fh, '<', $file or die "can't open $file: $!"; 
local $/ = ' '; 
while (my $num = <$fh>) { 
    print "$_ " for $num..$num+4; 
    print "\n"; 
} 

Волшебное 4 могут быть закодированы с помощью предварительной обработки всей линии, чтобы найти длину последовательности, скажем,

my $len =() = $line =~ /(\d+)/g; 

или путем split -ную в массив и с его scalar, а затем с помощью $len-1.


Дополнительные комментарии.

  • Я рекомендую три аргумента, открытый open my $fh, '<', $file

  • При просмотре вызова Распечатайте эту ошибку, die "Your message: $!", чтобы увидеть причину неудачи. Если вы решите бросить, if ($bad) { die "Got $bad" }, то вам может не понадобиться $!. Но когда внешний вызов не сработает, вы не знаете, поэтому вам нужна подходящая переменная ошибки, чаще всего $!.

+0

@jonasv Обновлено: добавлен другой метод (более похожий на OP), исправлен blooper в регулярном выражении, изменена печать для оптимизации. – zdim

1

Здесь нет необходимости использовать вложенный цикл, это всегда программа замедляется.

#!/usr/bin/perl 
use strict; 
use warnings; 

my @num = split(" ",(<DATA>)[0]); 

foreach my $inc (0..$#num) 
{ 
    print map{$inc+$_," "}@num; # Add one by one in array element 
    print "\n"; 
} 


__DATA__ 
1 2 3 4 5 
0

У вашей программы есть ряд проблем. Вот что останавливает его работу

  • Вы устанавливаете разделитель записи на одно место. Ваш входной файл содержит "1 2 3 4 5\n", поэтому цикл while будет повторять пять раз настройку $line в "1 ", "2 ", "3 ", "4 ", "5\n"

  • Вашего цикл for настроен на итерацию пять раз. Он делает chomp $line, который удаляет пробел после номера, затем увеличивает $line и печатает его. Затем вы выпрыгиваете из цикла for, выполнив его только один раз, с next OUT.Это приводит к каждому значению в файле время увеличивается на единицу и печатной, так что вы получите 2 3 4 5 6

  • Удаление ненужных next OUT, производит что-то ближе

    2 3 4 5 6 3 4 5 6 7 4 5 6 7 8 5 6 7 8 9 6 7 8 9 10 
    

    Там теперь пять чисел печатаются для каждого числа входной файл

  • Добавление print "\n" после помощи в for петли разделения линий

    2 3 4 5 6 
    3 4 5 6 7 
    4 5 6 7 8 
    5 6 7 8 9 
    6 7 8 9 10 
    
  • Теперь нам нужно напечатать номер до, он будет увеличен вместо после этого. Если поменять местами $line += 1 и print "$line " мы получаем это

    1 2 3 4 5 
    2 3 4 5 6 
    3 4 5 6 7 
    4 5 6 7 8 
    5 
    6 7 8 9 
    

    Что происходит здесь является то, что 5 по-прежнему следует быть символом новой строкой, которая теперь появляется на выходе. chomp не удалит это, потому что он удаляет значение $/ с конца строки. Вы установили это в пространство, чтобы удалить только пробелы. Исправление состоит в том, чтобы заменить chomp на замещение s/\s+//g, которое удаляет * все пробелы из строки. Кроме того, необходимо сделать это только один раз, так что я положил его вне цикла for в верхней

Теперь мы получаем это

1 2 3 4 5 
    2 3 4 5 6 
    3 4 5 6 7 
    4 5 6 7 8 
    5 6 7 8 9 

И это ваш код, как это закончилось

use strict; 
use warnings; 

open("handle", 'numbers.txt') or die('unable to open numbers file\n'); 

$/ = ' '; 

for my $line (<handle>) { 

    $line =~ s/\s+//g; 

    for (my $a = 0; $a < 5; $a++) { 
     print "$line "; 
     $line += 1; 
    } 

    print "\n"; 
} 

close("handle"); 

Есть несколько других передовых методов, которые могли бы улучшить вашу программу

  • Используйте use warnings 'all'

  • Используйте ручки лексических файлов и форма трехпараметрической open

  • Используйте local, если вы меняете Perl встроенных в переменных

  • Put $! в вашу die строки чтобы вы знали , почему не удалось получить open

  • избежать C-стиля for цикла, и перебрать список вместо

Создание этих исправлений и выглядит следующим образом. Выход идентичен выше

use strict; 
use warnings 'all'; 

open my $fh, '<', 'numbers.txt' 
     or die qq{Unable to open "numbers.txt" for input: $!}; 

local $/ = ' '; 

for my $line (<$fh>) { 

    $line =~ s/\s+//g; 

    for my $a (0 .. 4) { 
     print "$line "; 
     ++$line; 
    } 

    print "\n"; 
} 
Смежные вопросы