2009-07-10 4 views
4

Я новичок в Perl. Знайте немного C хотя. Я наткнулся на этот фрагмент в одном из наших классных нот:Что делает после печати в Perl?

$STUFF="c:/scripts/stuff.txt"; 

open STUFF or die "Cannot open $STUFF for read :$!"; 

print "Line $. is : $_" while (<STUFF>); 

Почему while после print заявления? Что оно делает?

+0

Сколько лет этой книге? –

+2

** 'WARNING' ** Не используйте этот код, он плохо написан. –

+1

Ой, да, я даже не заметил, что он делает с файловым дескриптором. Это зло. – chaos

ответ

10

Это то же самое, как

while (<STUFF>) { 
    print "Line $. is : $_"; 
} 

Она написана так, как это происходит потому, что это проще и компактнее. Это, в целом, Perl's (in) известная форма «модификатор выражения» для условностей и циклов.

+1

Я бы не согласился с тем, что это «проще» (если бы это был, этого вопроса не было бы!) – dbr

+2

Это проще. То, что это не является интуитивно очевидным для каждого человека для каждого фона. Когда вы судите, насколько две вещи проще или сложнее относительно друг друга, я действительно думаю, что вам нужно работать с предположением, что зритель знает, что означает, а не означает «о, это сложнее, потому что я знаю, C а не Perl ". – chaos

+0

Это более компактный, не обязательно простой. Я нахожу это примерно так же просто, но я уже давно знаю Perl. –

4

Следующие фрагменты точно эквивалентными, просто разные способы написать то же самое:

print "Line $. is : $_" while (<STUFF>); 

while (<STUFF>) { 
    print "Line $. is : $_"; 
} 

Что это делает каждая итерация цикла, Perl читает один строка текста из файла STUFF и помещает его в специальную переменную $_ (это то, что делают угловые скобки). Затем тело линий печатает цикл вроде:

Line 1 is : test 
Line 2 is : file

Специальная переменная $. является линия номер последней строки, прочитанной из файла, и $_ является содержимое этой линии, задается оператором угол кронштейна.

3

После того, как печать была напечатана, сделайте линию прочитанной почти как обычный английский. Он также делает упор на печать вместо времени. И вам не нужны фигурные скобки: { ... }

Можно также использовать, если и если, например,

print "Debug: foobar=$foobar\n" if $DEBUG; 

print "Load file...\n" unless $QUIET; 
+2

Спасибо, что сообщили мне об abt 'if' и 'if', прежде чем я отправил это тоже в stackoverflow :-) – 2009-07-10 11:54:55

1

Обратите внимание, что while оператор может следовать только тело цикла, если это один вкладыш. Если тело цикла работает по нескольким строкам, то перед ним должен стоять while.

+0

это больше похоже на C; thanks :-) – 2009-07-10 11:54:15

+1

PERL заимствует свой синтаксис с нескольких разных языков, включая английский. Позволяя условному утверждению следовать за однострочным блоком, он читает больше как английский. Вы также можете посмотреть слова 'except' и' until', которые действуют как отрицательные версии 'if' и' while'. Это то, что C не имеет, насколько я знаю. Использование его иногда улучшает читаемость вашего кода. – Zaid

6

Другие ответы объяснили форму модификатора оператора цикла while. Однако здесь есть много другой магии. В частности, сценарий основывается на трех специальных переменных Perl. Два из них ($_ и $!) очень распространены; другой ($.) достаточно распространен. Но они все знают.

Когда вы запускаете while <$fh> на открытую файловую дескриптор, Perl автоматически проходит через файл по строкам, пока не достигнет EOF. Внутри каждого цикла текущая строка устанавливается на $_, если вы ничего не делаете. Таким образом, эти две такие же:

while (<$fh>) { # something } 
while (defined($_ = <$fh>)) { # something } 

См perldoc perlop, в разделе операторов ввода/вывода. (Некоторые люди находят это слишком магическим, поэтому вместо этого они используют while (my $line = <$fh>).Это дает вам $line для каждой строки, а не $_, что является более ясным именем переменной, но для этого требуется больше ввода. Каждому принадлежит.)

$! содержит значение системной ошибки (если установлено). См. Раздел perldoc perlvar, раздел о $OS_ERROR, чтобы узнать, как и когда его использовать.

$. содержит номер строки. См. perldoc perlvar, раздел на $NR. Эта переменная может быть удивительно сложной. Он не обязательно будет содержать номер строки файла, который вы сейчас читаете. Пример:

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

while (<>) { 
    print "$ARGV: $.\n"; 
} 

Если вы сохраните это как lines и запустить его как perl lines file1 file2 file3, то Perl будет считать строки прямо через file1, file2 и file3. Вы можете видеть, что Perl знает, какой файл он читает (он находится в $ ARGV, имена файлов будут правильными), но он не автоматически переводит нумерацию строк в конце каждого файла. Я упоминаю об этом, так как я немного походил на это поведение несколько раз, пока не получил его через мой (толстый) череп. Вы можете сбросить нумерацию для отслеживания отдельных файлов таким образом:

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

while (<>) { 
    print "$ARGV: $.\n"; 
} 
continue { 
    close ARGV if eof; 
} 

Вы должны также проверить strict и warnings прагм и посмотреть на новой, три-аргументе форме open. Я только заметил, что вы «unknown (google)», что означает, что вы, вероятно, никогда не вернетесь. Наверное, по крайней мере, у меня была практика набора текста на день.

+2

Хороший лорд! И я подумал, что C - самый сложный язык. Perl также делает много скрытых вещей. Что касается неизвестного (google), я сейчас студент; слишком много учителей здесь для меня, чтобы разоблачить себя :-), может быть, позже я постараюсь быть собой. Я дал вам ваш +1 BTW :-) – 2009-07-10 12:32:26

+0

Я не беспокоился о репутации (хотя спасибо). Просто было бы стыдно набирать все это, а не читать. Рад, что вы это видели. У меня минимальный опыт работы с C, поэтому я не могу сравнивать. Но я считаю, что осложнения Перла в основном облегчают вашу жизнь. Perl будет очень, очень часто автоматически делать то, что вы хотите. Это хорошо. – Telemachus

3

Я взял на себя смелость переписать свой фрагмент, как я.

Ниже моего предлагаемого кода галерея изгоев менее оптимальных методов, которые вы можете увидеть в дикой природе.

use strict; 
use warnings; 

my $stuff_path = 'c:/scripts/stuff.txt'; 

open (my $stuff, '<', $stuff_path) 
    or die "Cannot open'$stuff_path' for read : $!\n"; 

# My preferred method to loop over a file line by line: 
# while loop with explicit variable 
while(my $line = <$stuff>) { 
    print "Line $. is : $line\n"; 
} 

Другие способы, которые вы можете видеть. Каждый из них может быть заменен циклом while в моем примере выше.

# while statement modifier 
# - OK, but less clear than explicit code above. 
print "Line $. is : $_" while <$stuff>; 

# while loop 
# - OK, but if I am operating on $_ explicitly, I prefer to use an explicit variable. 
while(<$stuff>) { 
    print "Line $. is : $_"; 
} 

# for statement modifier 
# - inefficient 
# - loads whole file into memory 
print "Line $. is : $_" for <$stuff>; 

# for loop - inefficient 
# - loads whole file into memory; 
for(<$stuff>) { 
    print "Line $. is : $_\n"; 
} 

# for loop with explicit variable 
# - inefficient 
# - loads whole file into memory; 
for my $line (<$stuff>) { 
    print "Line $. is : $line\n"; 
} 

# Exotica - 

# map and print 
# - inefficient 
# - loads whole file into memory 
# - stores complete output in memory 
print map "Line $. is : $_\n", <$stuff>; 

# Using readline rather than <> 
# - Alright, but overly verbose 
while(defined (my $line = readline($stuff)) { 
    print "Line $. is : $line\n";  
} 

# Using IO::Handle methods on a lexical filehandle 
# - Alright, but overly verbose 
use IO::Handle; 
while(defined (my $line = $stuff->readline)) { 
    print "Line $. is : $line\n";  
} 
Смежные вопросы