2010-08-25 10 views
2

Я новичок в Perl, и у меня проблема при чтении файла по строкам. Я начал с учебника, который предложил использовать цикл while. Это работало нормально, однако я хотел иметь возможность выйти из цикла в случае ошибки. Я знаю, что могу использовать «последнее» ключевое слово, но мне это не очень нравится, я хотел бы включить его в булевское выражение while, чтобы было легче видеть, на каких условиях он останавливается. Так что я сделалPerl while loop/read file

$error=0; 
while ((!$error) && (<MYFILE>)) { 
print $_; 
...  
} 

К сожалению, это не работает, потому что $ _, кажется, содержит «неинициализированное значение». По какой-то причине, когда я меняю (! $ Error) на (! 0), он снова работает. Я бы понял, что он не работал, если бы я использовал || из-за ленивой оценки, но с & & в этом случае обе стороны должны быть оценены, поэтому я не понимаю, почему она не инициализирует переменную строки.

+6

Изучите идиомы изучаемого вами языка (любой язык) - и 'last' - одна из идиом Perl. –

+1

Как я уже сказал в вопросе, я знаю о последнем ключевом слове. – bufferUnderrun

+1

Итак, научитесь * обнимать * идиомы языка. –

ответ

5

Магическое назначение $_ происходит только тогда, когда нет ничего другого в цикле:

while (<MYFILE>) { 
    print $_; 
    ...  
} 

Если вы хотите тест ошибки тоже - что не рекомендуется - тогда вам нужно выполнить задание:

my $error = 0; 
while (!$error && ($_ = <MYFILE>)) { 
    print; 
    $error = 1 if m/quit/i; 
} 

не забудьте добавить:

use warnings; 
use strict; 

причина, почему версия sion с '!0' работал, вероятно, потому, что Perl оптимизирует и распознает, что '!0' всегда верно и удаляет его из цикла, оставляя только оператор ввода-вывода, который затем присваивает $_.

NB: это гораздо лучше использовать идиоматических Perl и last заявление:

while (<MYFILE>) { 
    print; 
    last if m/quit/i; 
} 
+0

Я считаю, что вам нужно добавить «определенную» проверку на $ _ в условие цикла while, иначе строка в файле, содержащем «0», будет оцениваться как ложная и закончить цикл. Итак, что-то вроде: while (! $ Error && defined ($ _ = )) {... –

+0

Хорошо, спасибо, я не знал о природе цикла. Я думал, что это улучшит читаемость, если все условия для цикла будут в одном месте. В университете меня учили GOTO и - в меньшей степени - заявления о разводе - это зло, поэтому я всегда старался их избегать. Но я буду использовать предложенную вами версию. – bufferUnderrun

+0

@Matthew: нет, вам не нужно это делать. Строка также содержит новую строку (ее нужно удалить «chomp», если требуется). Я предполагаю, что если файл заканчивается символом новой строки, за которым следует 0 (и нет конечной новой строки), тогда вы можете быть прав - но это не стандартный текстовый файл. –

3

Сначала, как Джонатан указывает, что вы всегда должны писать языки идиоматически, если у вас есть очень веские основания и здесь вы не» т.

Ваша большая проблема - непонимание петли while. Автоматическое присвоение результата оператора угла $_ происходит только в том случае, если это единственное условие в условном тесте while. Если в условном тесте имеется несколько элементов, они вычисляются и затем отбрасываются (Программирование Perl с. 80-81 и I/O Operators at Perldoc).