Как мне остановить 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
}
Я собираюсь остановиться там. Я надеюсь, что это даст вам некоторое представление о том, что не так с вашим кодом. Боюсь, что этот уровень неправильности пронизывает и весь ваш код.