Как мне остановить STDIN в массиве? (PERL)

Мой @array не перестанет принимать в STDIN...

my @array = undef;
while (@array = undef){
    @array = <STDIN>;
    for (@array[x]=5){
        @array = defined;
    }
}

2 ответа

Решение

Как выяснилось, ограничить STDIN до пяти строк

use warnings;
use strict;
use feature 'say';

my @input;

while (<STDIN>) {
    chomp;
    push @input, $_;
    last if @input == 5;
}

say for @input;

Есть другие вещи, чтобы комментировать в размещенном коде. Хотя многое из этого подробно объясняется в ответе Дейва Кросса, я хотел бы обратиться к контексту при чтении из файлового дескриптора.

"Алмазный" оператор <> контекстно-зависимый. От операторов ввода / вывода (perlop)

Если <FILEHANDLE> используется в контексте, который ищет список, возвращается список, содержащий все строки ввода, по одной строке на элемент списка. Таким образом, легко получить достаточно большое пространство данных, поэтому используйте его с осторожностью.

В обычном while зациклить <> находится в скалярном контексте

while (my $line = <$fh>)

и то же самое с while (<$fh>) так как он присваивает $_ переменная, скаляр, по умолчанию.

Но если мы присвоим массиву, скажем, из файлового дескриптора $fh с которой был открыт файл

my @lines = <$fh>;

затем <> Оператор работает в контексте списка. Он читает все строки, пока не увидит EOF (конец файла), после чего он возвращает все строки, которые назначены @lines, Помните, что каждая строка имеет новую строку. Вы можете удалить их все

chomp @lines;

поскольку chomp работает и над списком.

С STDIN это вызывает проблему, когда ввод поступает с клавиатуры, как <> ждет большего ввода, так как EOF не придет сам по себе. Обычно дается как Ctrl+D в системах Unixy (Ctrl+Z в Windows).

Таким образом, вы можете, в принципе, иметь @array = <STDIN> и выйти из ввода с Ctrl+D но это может быть немного неудобно для ввода, ожидаемого от клавиатуры, так как это в основном подразумевает необходимость построчной обработки. Это менее необычно, если STDIN приходит из файла,

script.pl < input.txt

или труба в командной строке

some command with output | script.pl

где мы получаем EOF (любезно предоставлено EOT).

Но я бы все равно придерживался привычного while при чтении STDINи обрабатывать его построчно.


Ctrl+D как это обычно называют, но один на самом деле печатает нижний регистр d с Ctrl, Обратите внимание, что Ctrl а также c (помечено как Ctrl+C) делает что-то совершенно другое; он отправляет SIGINT сигнал, который завершает всю программу, если не пойман.

my @array = undef;
while (@array = undef){

Эти две строки не делают то, что (я полагаю) вы думаете, что они делают.

my @array = undef;

Это определяет массив с единственным элементом, который является специальным значением undef, Я подозреваю, что вы на самом деле хотели:

my @array = ();

который создает пустой массив. Но при первом создании массивы Perl всегда пусты, поэтому это можно упростить до:

my @array;

Вторая строка повторяет эту ошибку и добавляет новую.

while (@array = undef) {

Я подозреваю, что вы хотите проверить наличие пустого массива здесь, и вы пытались найти что-то, что означало что-то вроде @array is undefined). Но вы упустили тот факт, что в Perl операторы присваивания (как =) отличаются от операторов сравнения (например, ==). Так что эта строка назначает undef в @array а не сравнивать это. Вы действительно хотели @array == undef - но это тоже не правильно.

Вам нужно отойти от этой идеи проверки того, что массив "определен". На самом деле вас интересует, является ли массив пустым. И у Perl есть хитрый трюк, который поможет вам в этом разобраться.

Если вы используете массив Perl в месте, где Perl ожидает увидеть единственное (скалярное) значение, он дает вам количество элементов в массиве. Таким образом, вы можете написать код, как:

my $number_of_elements = @an_array;

Логическая проверка в if или же while условие - единственное скалярное значение. Так что, если вы хотите проверить, содержит ли массив какие-либо элементы, вы можете использовать такой код:

if (@array) {
  # @array contains data
} else {
  # @array is empty
}

И чтобы выполнить цикл, пока массив содержит элементы, вы можете просто написать:

while (@array) {
  # do something
}

Но здесь вы хотите что-то сделать, пока ваш массив пуст. Для этого вы можете либо инвертировать while логика условий (используя ! для "не"):

while (!@array) {
  # do something
}

Или вы можете переключиться на использование until тест (который является противоположностью while):

until (@array) {
  # do something
}

Я собираюсь остановиться там. Я надеюсь, что это даст вам некоторое представление о том, что не так с вашим кодом. Боюсь, что этот уровень неправильности пронизывает и весь ваш код.

Другие вопросы по тегам