Perl (учусь)

Модератор: Модераторы разделов

Аватара пользователя
ripke
Сообщения: 85
ОС: Ubuntu 9.04, x86_64

Perl

Сообщение ripke »

Нужно угадать случайное число из десяти. При этом чтобы каждый раз при неверном наборе выводилась подсказка - больше или меньше. Вот я сделал (только начал изучать недавно).Скажите можно сделать лучше?

Код: Выделить всё

 1 #! /usr/bin/perl -w encoding 'utf8'
  2
  3 $im_thinking_of=int(rand(10));
  4 print "Введите часло от 0 до 9:";
  5 $guess=<STDIN>;
  6 #chomp $guess; # Нe забудьте удалить символ новой строка!
  7
  8 while ($guess>$im_thinking_of) {
  9 print "Перебор\n"; $guess=<STDIN>
 10 }
 11 while ($guess<$im_thinking_of) {
 12 print "Недобор\n"; $guess=<STDIN>
 13 }
 14 if ($guess==$im_thinking_of) {
 15 print "Угадали\n"
 16 }
Спасибо сказали:
Аватара пользователя
ZyX
Сообщения: 355
ОС: Gentoo

Re: Perl

Сообщение ZyX »

ripke писал(а):
05.04.2010 10:55
Нужно угадать случайное число из десяти. При этом чтобы каждый раз при неверном наборе выводилась подсказка - больше или меньше. Вот я сделал (только начал изучать недавно).Скажите можно сделать лучше?

Код: Выделить всё

 1 #! /usr/bin/perl -w encoding 'utf8'
  2
  3 $im_thinking_of=int(rand(10));
  4 print "Введите часло от 0 до 9:";
  5 $guess=<STDIN>;
  6 #chomp $guess; # Нe забудьте удалить символ новой строка!
  7
  8 while ($guess>$im_thinking_of) {
  9 print "Перебор\n"; $guess=<STDIN>
 10 }
 11 while ($guess<$im_thinking_of) {
 12 print "Недобор\n"; $guess=<STDIN>
 13 }
 14 if ($guess==$im_thinking_of) {
 15 print "Угадали\n"
 16 }

Во-первых, сделайте нормальные отступы. Во-вторых, заявленную задачу скрипт не
решает: например, для случайного числа 5:

Код: Выделить всё

Введите часло от 0 до 9:
0
Недобор
9
<Скрипт завершил работу>

В-третьих, сразу привыкайте писать с use strict;. В-четвёртых, не пишите всё
в одну строку (я про print "..."; $guess=<STDIN>) и не забывайте везде ставить
«;», даже если её можно опустить. И, в-пятых, что такое «часло»?
Спасибо сказали:
Аватара пользователя
ripke
Сообщения: 85
ОС: Ubuntu 9.04, x86_64

Re: Perl

Сообщение ripke »

Во как! Значит я проperlся. А что часло, так это ничаго, очапятка, как говорится. Спасибо за советы, буду думать дальше )). (чего это он пять не угадывает?)
Во-вторых, заявленную задачу скрипт не
решает: например, для случайного числа 5:

Сейчас вот проверил, подставил в переменную число 5 у меня все решилось.
~$ /home/evgeny/perl.pl
Введите часло от 0 до 9:5
Угадали
С синтаксисом понятно, а как насчет функциональности? Я как новичок переживаю, что код сделан несерьезно как-то )).
Спасибо сказали:
Аватара пользователя
diesel
Бывший модератор
Сообщения: 5989
ОС: OS X, openSuSE, ROSA, Debian

Re: Perl

Сообщение diesel »

ripke писал(а):
06.04.2010 11:54
(чего это он пять не угадывает?)

0<5 - он проскакивает на второй цикл
9>5 - на первый цикл мы уже не попадаем, условию второго это не удовлетворяет, и условию последнего if'а тоже. Поэтому просто выходим.
Спасибо сказали:
Аватара пользователя
ripke
Сообщения: 85
ОС: Ubuntu 9.04, x86_64

Re: Perl

Сообщение ripke »

diesel писал(а):
06.04.2010 12:06
ripke писал(а):
06.04.2010 11:54
(чего это он пять не угадывает?)

0<5 - он проскакивает на второй цикл
9>5 - на первый цикл мы уже не попадаем, условию второго это не удовлетворяет, и условию последнего if'а тоже. Поэтому просто выходим.

следовательно я чайник)), спасибо, вопросов больше нет (пока)
Спасибо сказали:
Аватара пользователя
ripke
Сообщения: 85
ОС: Ubuntu 9.04, x86_64

Re: Perl

Сообщение ripke »

Поспешил. Еще такой вопрос. Мне кажется, стоит еще почитать про вложенные циклы, я прав?
Спасибо сказали:
Аватара пользователя
diesel
Бывший модератор
Сообщения: 5989
ОС: OS X, openSuSE, ROSA, Debian

Re: Perl

Сообщение diesel »

ripke писал(а):
06.04.2010 12:38
Поспешил. Еще такой вопрос. Мне кажется, стоит еще почитать про вложенные циклы, я прав?

да нет. Вам нужно придумать более прямое решение задачи(в котором будет например один while и один if с некоторым количеством elsif и else)
Спасибо сказали:
Аватара пользователя
ripke
Сообщения: 85
ОС: Ubuntu 9.04, x86_64

Re: Perl

Сообщение ripke »

Ура, кажется я сделал. Но мне этот код все равно не нравится, хотя он определенно рабочий

Код: Выделить всё

#! /usr/bin/perl -w encoding 'utf8'

$im_thinking_of=int(rand(10));
print "Введите число от 0 до 9:";
$guess=<STDIN>;

while ($guess>$im_thinking_of or $guess<$im_thinking_of or $guess==$im_thinking_of) {
        if ($guess<$im_thinking_of) {
        print "Недобор\n";
        $guess=<STDIN>;
}               elsif ($guess>$im_thinking_of) {
                print "Перебор\n";
                $guess=<STDIN>;
}                       last if ($guess==$im_thinking_of) and
                        print "Угадали\n";
}

По поводу use strict;
Когда я это прописываю, скрипт выдает ошибки

Код: Выделить всё

Global symbol "$im_thinking_of" requires explicit package name at /home/evgeny/perl.pl line 4.
Global symbol "$guess" requires explicit package name at /home/evgeny/perl.pl line 6.
Global symbol "$guess" requires explicit package name at /home/evgeny/perl.pl line 8.
Global symbol "$im_thinking_of" requires explicit package name at /home/evgeny/perl.pl line 8.
Global symbol "$guess" requires explicit package name at /home/evgeny/perl.pl line 8.
Global symbol "$im_thinking_of" requires explicit package name at /home/evgeny/perl.pl line 8.
Global symbol "$guess" requires explicit package name at /home/evgeny/perl.pl line 8.
Global symbol "$im_thinking_of" requires explicit package name at /home/evgeny/perl.pl line 8.
Global symbol "$guess" requires explicit package name at /home/evgeny/perl.pl line 9.
Global symbol "$im_thinking_of" requires explicit package name at /home/evgeny/perl.pl line 9.
Global symbol "$guess" requires explicit package name at /home/evgeny/perl.pl line 11.
Global symbol "$guess" requires explicit package name at /home/evgeny/perl.pl line 12.
Global symbol "$im_thinking_of" requires explicit package name at /home/evgeny/perl.pl line 12.
Global symbol "$guess" requires explicit package name at /home/evgeny/perl.pl line 14.
Global symbol "$guess" requires explicit package name at /home/evgeny/perl.pl line 15.
Global symbol "$im_thinking_of" requires explicit package name at /home/evgeny/perl.pl line 15.
Execution of /home/evgeny/perl.pl aborted due to compilation errors.

Честно говоря, я не знаю (пока) что такое use strict )), поэтому это не использую.
Еще одно... Вообще-то мне бы хотелось сделать вот так через метку (я почему-то полагал что таким образом я смогу зациклить круг, но похоже, что ошибаюсь). Можете объяснить почему не происходит перехода к метке в этом коде?

Код: Выделить всё

#! /usr/bin/perl -w encoding 'utf8'
#use strict;

$im_thinking_of=5;# (rand(10));
print "Введите часло от 0 до 9:";
$guess=<STDIN>;
#chomp $guess; # Be забудьте удалить символ новой строка!

MYBLOCK:  while ($guess>$im_thinking_of) {
print "Перебор\n"; $guess=<STDIN>
}
while ($guess<$im_thinking_of) {
print "Недобор\n"; $guess=<STDIN>
}
if ($guess==$im_thinking_of) {
print "Угадали\n"
} else {
MYBLOCK
}
Спасибо сказали:
Аватара пользователя
diesel
Бывший модератор
Сообщения: 5989
ОС: OS X, openSuSE, ROSA, Debian

Re: Perl

Сообщение diesel »

ripke писал(а):
06.04.2010 16:57
Ура, кажется я сделал. Но мне этот код все равно не нравится, хотя он определенно рабочий

Код: Выделить всё

#! /usr/bin/perl -w encoding 'utf8'

$im_thinking_of=int(rand(10));
print "Введите число от 0 до 9:";
$guess=<STDIN>;
while ($guess>$im_thinking_of or $guess<$im_thinking_of or $guess==$im_thinking_of) {
        if ($guess<$im_thinking_of) {
            print "Недобор\n";
            $guess=<STDIN>;
                 }elsif ($guess>$im_thinking_of) {
             print "Перебор\n";
             $guess=<STDIN>;
                 }
         last if ($guess==$im_thinking_of) and  print "Угадали\n";
}

ок, обратите внимание:

Код: Выделить всё

while ($guess>$im_thinking_of or $guess<$im_thinking_of or $guess==$im_thinking_of) {

описывает любую ситуацию(кроме той когда введено не число, но это пока опустим), поэтому, можно просто while(1){

Вы три раза делаете: $guess=<STDIN>; вместо этого можно просто его внести в цикл:

Код: Выделить всё

while(1){
   $guess=<STDIN>;
   chomp $guess; # таки нужно отрезать \n
   if ($guess<$im_thinking_of) {
            print "Недобор\n";
   }elsif($guess>$im_thinking_of) {
             print "Перебор\n";
   }elsif($guess==$im_thinking_of){
        print "Угадали\n";
        last;
    }
}



ripke писал(а):
06.04.2010 16:57
По поводу use strict;
Когда я это прописываю, скрипт выдает ошибки
Честно говоря, я не знаю (пока) что такое use strict )), поэтому это не использую.

http://eax.me/perl-basics-part3/ - это страховка от ошибок.

ripke писал(а):
06.04.2010 16:57
Еще одно... Вообще-то мне бы хотелось сделать вот так через метку (я почему-то полагал что таким образом я смогу зациклить круг, но похоже, что ошибаюсь).

Можно, не ошибаетесь, но... НИКОГДА ТАК НЕ ДЕЛАЙТЕ!


ripke писал(а):
06.04.2010 16:57
Можете объяснить почему не происходит перехода к метке в этом коде?

Код: Выделить всё

#! /usr/bin/perl -w encoding 'utf8'
#use strict;

$im_thinking_of=5;# (rand(10));
print "Введите часло от 0 до 9:";
$guess=<STDIN>;
#chomp $guess; # Be забудьте удалить символ новой строка!

MYBLOCK:  while ($guess>$im_thinking_of) {
print "Перебор\n"; $guess=<STDIN>
}
while ($guess<$im_thinking_of) {
print "Недобор\n"; $guess=<STDIN>
}
if ($guess==$im_thinking_of) {
print "Угадали\n"
} else {
MYBLOCK
}

если как раз таки вставить use strict:

Код: Выделить всё

diesel@indie:~$ cat tmp.pl
#! /usr/bin/perl
use strict;
use warnings;

my $im_thinking_of=5;# (rand(10));
print "Введите часло от 0 до 9:";
my $guess=<STDIN>;
chomp $guess; # Be забудьте удалить символ новой строка!

MYBLOCK:  while ($guess>$im_thinking_of) {
    print "Перебор\n";
    $guess=<STDIN>;
    chomp $guess;
}
while ($guess<$im_thinking_of) {
    print "Недобор\n";
    $guess=<STDIN>;
    chomp $guess;
}

if ($guess==$im_thinking_of) {
    print "Угадали\n"
} else {
    MYBLOCK
}

и запустить, мы узнаем что:

Код: Выделить всё

diesel@indie:~$ ./tmp.pl
Bareword "MYBLOCK" not allowed while "strict subs" in use at ./tmp.pl line 24.
Execution of ./tmp.pl aborted due to compilation errors.

Вобщем, что-то не так. Потому что: http://en.wikipedia.org/wiki/Perl_control_structures#goto :

if ($guess==$im_thinking_of) {
print "Угадали\n"
} else {
goto MYBLOCK
}
Спасибо сказали:
Аватара пользователя
ripke
Сообщения: 85
ОС: Ubuntu 9.04, x86_64

Re: Perl

Сообщение ripke »

Здорово, как всегда. Нравится perl и этот форум).
описывает любую ситуацию(кроме той когда введено не число, но это пока опустим)

А если вставить что-нибудь типа

Код: Выделить всё

BEGIN {
$guess=='\d*' or
warn "Число давай\n" and
exit 255;
        }

в теле цикла сразу после объявления my $guess. Поскольку я паралельно читаю про рег выражения, то тупо добавли этот метасимвол \d )). Чую, такое не прокатит. А как можно?
Спасибо сказали:
Аватара пользователя
diesel
Бывший модератор
Сообщения: 5989
ОС: OS X, openSuSE, ROSA, Debian

Re: Perl

Сообщение diesel »

$guess =~ '\d*'

вернее
$guess =~ /^\d+$/

нас интересует только числа.
отдельный блок для этого не нужен, да и выходить не обязательно.
Спасибо сказали:
Аватара пользователя
ripke
Сообщения: 85
ОС: Ubuntu 9.04, x86_64

Re: Perl

Сообщение ripke »

Вот еще. Решил посмотреть как работает оператор диапазона, интереса ради.

Код: Выделить всё

@ubuntu:~$ perl -wl -e 'use encoding 'utf8'; print (а..я);'
Unrecognized character \xD0 in column 27 at -e line 1.

Опять дискриминация русского языка? )) Почему?
С английским порядок

Код: Выделить всё

@ubuntu:~$ perl -wl -e 'use encoding 'utf8'; print (a..z);'
Unquoted string "a" may clash with future reserved word at -e line 1.
Unquoted string "z" may clash with future reserved word at -e line 1.
abcdefghijklmnopqrstuvwxyz
Спасибо сказали:
pcodr
Сообщения: 283
ОС: Debian

Re: Perl

Сообщение pcodr »

ripke писал(а):
08.04.2010 07:57
Вот еще. Решил посмотреть как работает оператор диапазона, интереса ради.

Код: Выделить всё

@ubuntu:~$ perl -wl -e 'use encoding 'utf8'; print (а..я);'
Unrecognized character \xD0 in column 27 at -e line 1.

Опять дискриминация русского языка? )) Почему?
С английским порядок

Код: Выделить всё

@ubuntu:~$ perl -wl -e 'use encoding 'utf8'; print (a..z);'
Unquoted string "a" may clash with future reserved word at -e line 1.
Unquoted string "z" may clash with future reserved word at -e line 1.
abcdefghijklmnopqrstuvwxyz


Во-первых строки нужно заключать в кавычки. Поэтому правильно будет так: print("а".."я");
Во-вторых perldoc perlop сообщает:
QUOTE писал(а):If the initial value specified isn't part of a magical increment sequence (that is, a non-empty string matching "/^[a-zA-Z]*[0-9]*\z/"), only the initial value will be returned. So the following will only return an alpha:

use charnames 'greek';
my @greek_small = ("\N{alpha}" .. "\N{omega}");


remote system type is unix
Спасибо сказали:
Аватара пользователя
ripke
Сообщения: 85
ОС: Ubuntu 9.04, x86_64

Re: Perl

Сообщение ripke »

Во-первых,

Код: Выделить всё

@ubuntu:~$ perl -lwe 'use charnames "cyrillic";  @rus_small=("\N{а}" .. "\N{я}"); print @rus_small;'
Unknown charname 'а' at -e line 1
Unknown charname 'я' at -e line 1
Wide character in print at -e line 1.
�

Во-вторых,

Код: Выделить всё

@ubuntu:~$ perl -lwe 'use charnames "cyrillic";  @rus_small=(\N{а} .. \N{я}); print @rus_small;'
Unrecognized character \xD0 in column 43 at -e line 1.

В-третьих, то, что сообщает perldoc perlop мне как неанглязычному пользователю, но тем не менее, владеющему для поверхностного понимания, так это лишь то, опять же с моей точки зрения (базовый английский), что отображаться будет лишь первая буква.
В-четвертых, ни код в параграфе выше с записью во-первых, ни код с записью во-вторых, ни чтение справки с записью в-третьих мне не помогли. Ставлю вопрос ребром. Можно отобразить русские буквы в ютф в операторе диапазона? Скажите, чего почитать.
Спасибо сказали:
Аватара пользователя
ripke
Сообщения: 85
ОС: Ubuntu 9.04, x86_64

Re: Perl

Сообщение ripke »

И вообще )). Хорош кошмарить новичка таким кодом

Код: Выделить всё

@ubuntu:~$ perl -lwe 'use charnames "cyrillic";  @rus_small=("\N{be}" .. "\N{ya}"); print @rus_small;'
Wide character in print at -e line 1.
б

Мало того, что он выводит только первую букву, так еще и выглядит угрожающе.

P.S. Спустя несколько секунд, почитав повнимательнее perldoc perlop, признаю, что работает вот так

Код: Выделить всё

@ubuntu:~$ perl -lwe 'use charnames "cyrillic";  @rus_small= map { chr } ( ord("\N{a}") ..ord( "\N{ya}")); print @rus_small;'
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
Wide character in print at -e line 1.
абвгдежзийклмнопрстуфхцчшщъыьэюя

Во-первых, что означает куча строк с wide character и во-вторых, а попроще ничего нету?
Спасибо сказали:
pcodr
Сообщения: 283
ОС: Debian

Re: Perl

Сообщение pcodr »

Поясню. В perlop сообщается о том, что оператор диапазона может генерировать последовательности только для определенного набора символов.
А именно для "/^[a-zA-Z]*[0-9]*\z/". Как видите кириллица сюда не входит.

Самый короткий способ генерации русского алфавита вероятно такой:

Код: Выделить всё

perl -e 'use encoding "utf8"; print map chr, (ord("а")..ord("я"))'


По поводу "wide character" смотрите perldoc perldiag. Один из способов избавиться от предупреждения используемая вами выше прагма use encoding "utf8"
remote system type is unix
Спасибо сказали:
Аватара пользователя
ripke
Сообщения: 85
ОС: Ubuntu 9.04, x86_64

Re: Perl

Сообщение ripke »

Есть текстовый файл, в котором местами есть строки типа "2010 слово 20 А слово". Задача в том, чтобы удалить пробел между цифрой 20 и буквой А. Мне кажется проще и надежнее воспользоваться в данном случае специальной переменной @F и разделить текст на поля. Кол-во полей в файле от 0 (есть пустые строки) до 5. Я решил сначала выделить 3 и 4 поля, а потом применить к ним подстановку с выражениями. Начал как всегда с теста и эксперимента ))
perl -wnla -e 'use encoding "utf8";(undef, undef, $number, $letter )=@F; print "$number$letter";' file.txt
Ожидал увидеть на экране 3 и 4 поля со словами, а получил это (последние две строки)
Use of uninitialized value $number in concatenation (.) or string at -e line 1, <> line 2992.
Use of uninitialized value $letter in concatenation (.) or string at -e line 1, <> line 2992.
Почему не срабатывает ключевое слово undef?
Спасибо сказали:
Аватара пользователя
diesel
Бывший модератор
Сообщения: 5989
ОС: OS X, openSuSE, ROSA, Debian

Re: Perl

Сообщение diesel »

ripke писал(а):
16.04.2010 12:08
Есть текстовый файл, в котором местами есть строки типа "2010 слово 20 А слово". Задача в том, чтобы удалить пробел между цифрой 20 и буквой А. Мне кажется проще и надежнее воспользоваться в данном случае специальной переменной @F и разделить текст на поля. Кол-во полей в файле от 0 (есть пустые строки) до 5. Я решил сначала выделить 3 и 4 поля, а потом применить к ним подстановку с выражениями. Начал как всегда с теста и эксперимента ))
perl -wnla -e 'use encoding "utf8";(undef, undef, $number, $letter )=@F; print "$number$letter";' file.txt
Ожидал увидеть на экране 3 и 4 поля со словами, а получил это (последние две строки)
Use of uninitialized value $number in concatenation (.) or string at -e line 1, <> line 2992.
Use of uninitialized value $letter in concatenation (.) or string at -e line 1, <> line 2992.
Почему не срабатывает ключевое слово undef?

ключевое слово undef срабатывает, ругается оно на то что вот в этом print "$number$letter" оказываются пустые значения, то есть ничего в третьем и четвертом полях нет.
Спасибо сказали:
Аватара пользователя
ripke
Сообщения: 85
ОС: Ubuntu 9.04, x86_64

Re: Perl

Сообщение ripke »

По поводу функции stat в "minimal perl" читаю пример
The call to stat can be parenthesized and
indexed as if it were an array. The example
accesses the second element (labeled
$ino in the format shown above), which
is the file’s inode number.

print "File $f's inode is: ",
(stat $f)[1];

Дальше пытаюсь посмотреть инод для файла /etc/passwd

Код: Выделить всё

:~$ perl -wl -e 'print  (stat "/etc/passwd")[1];'
syntax error at -e line 1, near ")["
Execution of -e aborted due to compilation errors.

В чем ошибка?
Спасибо сказали:
Аватара пользователя
diesel
Бывший модератор
Сообщения: 5989
ОС: OS X, openSuSE, ROSA, Debian

Re: Perl

Сообщение diesel »

Код: Выделить всё

diesel@heups:~$ perl -e 'printf "%d\n", (stat("/etc/passwd"))[1];'
83379
diesel@heups:~$ perl -e 'print "".((stat("/etc/passwd"))[1])."\n";'
83379
Спасибо сказали:
pcodr
Сообщения: 283
ОС: Debian

Re: Perl

Сообщение pcodr »

QUOTE писал(а):В чем ошибка?


Не хватает скобок. Интерпретатор решает, что первые скобки относятся к print, хотя вы имели ввиду другое.
Правильно:

Код: Выделить всё

perl -wl -e 'print  ((stat "/etc/passwd")[1]);'
remote system type is unix
Спасибо сказали: