Как можно еще остановить чтение из <STDIN> в массив?

Рейтинг: 0Ответов: 3Опубликовано: 02.04.2023

Задача. Напишите программу, читающую список строковых значений, каждое из которых находится в отдельной строке входных данных. Элементы списка выводятся в обратном порядке.

my @lines;
while (<STDIN>) {
    chomp;
    push (@lines,$_);
    last if ($_ eq "exit");
}
@lines = reverse @lines;
my $i = 0;
while ($i < scalar @lines) {
    print @lines[$i] . "\n";
    $i += 1;
}

Вопросы:

  1. Как остановить чтение из <STDIN> в массив ? (если не задать условие остановки явно не получается остановить чтение...)
  2. Остановка чтения из <STDIN> задается с помошью условие last if ($_ eq "exit"), если не задать то чтение продолжается и если нажать CTRL-Z то останавливается но введенные строки в массив не выводятся, как можно это решить ?
  3. Когда ввести строку "exit" для остановки чтения из <STDIN>, то в массив эта строка записывается, как можно этого избежать ?

Конечно можно решить 2 вопрос так: pop(@lines), если есть другие варианты был бы рад почитать... :-)

Спасибо за внимание!

Ответы

▲ 1Принят

если не задать условие остановки явно

А как ты хотел? Да, все условия нужно задавать явно. Это компьютер-сайнс, а не "битва экстрасенсов".

Ну, как вариант:

#!/usr/bin/perl

use Modern::Perl;
#
# ИЛИ, если не влом кнопки тыкать:
#
# use strict;
# use warnings;
# use feature qw/say/;
# список строковых значений? OK:
use utf8::all;
use open qw/:std :utf8/;

my @lines;
while (<>) {
    s/^\s+|\s+$//sm;
    $_ or last;
    push @lines, $_;
}
say for sort { как_хотишь } reverse @lines;
# или
# say for reverse sort { как_хотишь } @lines;

Тут объяснять бессмысленность этого учебного примера дольше, чем писать его.

▲ 1

Вот исправленный код на языке Perl, который читает список строк из стандартного ввода и выводит их в обратном порядке:

#!/usr/bin/perl

use strict;
use warnings;

my @lines;
while (my $line = <STDIN>) {
    chomp $line;
    last if $line eq "exit";
    push @lines, $line;
}

@lines = reverse @lines;

foreach my $line (@lines) {
    print "$line\n";
}

1.Для того чтобы остановить чтение из в массив, необходимо установить какое-то условие, при котором цикл чтения будет прерываться. В вашем случае, вы использовали условие last if ($_ eq "exit"), которое означает, что цикл будет прерван, когда строка, считанная из стандартного ввода, будет равна "exit". Таким образом, если вы хотите остановить чтение по другому условию, то нужно изменить это условие.

2.Если вы не задали условие остановки в вашем коде, то чтение из будет продолжаться бесконечно. Если вы хотите остановить чтение из вручную, то можно воспользоваться комбинацией клавиш Ctrl-D на Linux/Unix системах или Ctrl-Z на Windows, которая означает "конец файла". После нажатия этой комбинации, программа закрывает стандартный ввод, и вы можете продолжить выполнение кода. В вашем случае, если вы нажмете Ctrl-Z, то программы будет остановлена, и вы увидите введенные строки в массиве @lines.

3.Для того чтобы избежать записи строки "exit" в массив, нужно прервать цикл чтения до того, как эта строка будет добавлена в массив.

▲ 0

В задаче сказано, что значения надо вывестив обратном порядке. При этом ничего не сказано, что читать надо из стандартного ввода. Когда мы говорим в случае стандартного ввода то не могу придумать решения, кроме как читать все входные данные в переменную и после вывести массив в обратном порядке

#!/usr/bin/env perl 

use strict;
use warnings;
use utf8;
use v5.26.0;

my @lines = <STDIN>;
while ($_ = pop @lines) {
    say;
}

Из очевидных минусов - нам надо загрузить все данные в память. Но, если мы говорим о чтении файлов, то есть выход: модуль Tie::File, который будет работать медленно, но с минимальным потреблением памяти. Он ассоциирует массив с файлом и дальше с ним можно работать по аналогии. У модуля есть свои особенности, по этому перед примененим рекомендую изучить документацию.

Что касается второй части вопроса: после ввода Ctrl+Z скрипт уходит в фоновый режим и восстановить его работу можно командой fg. То есть, он не останавливается. Передать признак окнца файла из консоли можно сочетанием клавиш Ctrl+D.

Если же речь шла о перехвате сочетания клавиш Ctrl+C, то для этого следует переопределить спецпеременную %SIG:

$SIG{'INT'} = sub {print "Gotcha!\n"};