Perl практика
Модификаторы выражений.
Синтаксис:выражение if управляющее_выражение;
# эквивалентно
if(управляющее_выражение) { выражение; }
Оператор читается справа налево.
Другие формы с модификаторами:
выражение1 unless выражение2; выражение1 while выражение2; выражение1 until выражение2;
Пример:
chomp($n = ); $i = 1; $i *= 2 until $i > $n;
Эти формы нельзя вкладывать одну в другую!
Операции && и как управляющие структуры.
Операции && и в PERL можно рассматривать как управляющие структуры. Возможные варианты:if(это) { то; } то if это; это && то;
"логическое ИЛИ" работает, как оператор unless:
unless (это) { то; }
это то;
CGI-программа гостевой книги.
Создание файла:touch /usr/tmp/chatfile chmod 0666 /usr/tmp/chatfile
Блокирование доступа:
use Fcntl qw(:flock); # импортирует LOCK_EX, ... ... flock(CHANDLE, LOCK_EX) bail("Cannot flock $CHATNAME: !$");
Другие компоненты формы.
Пример:#/usr/bin/perl5 -w
use strict; use CGI qw(:standard);
print header; print start_html("Ice Cream Stand"), h1("Ice Cream Stand"); if(param()) { my $who = param("name"); my $flavor = param("flavor"); my $scoops = param("scoops"); my $taxrate = 1.0743; my $cost = sprintf("%.2f", $taxrate * (1.00 + $scoops*0.25)); print p("Ok, $who, have $scoops scoops of $flavor for\$$cost."); } else { print hr(); print start_form(); print p("What is your name? ", textfield("name")); print p("What flavor: ", popup_menu("flavor", ['mint', 'cherry', 'mocha'])); print p("How many scoops? ", popup_menu("scoops", [1..3])); print p(submit("order"), reset("clear")); print end_form(), hr(); } print end_html();
Другие вызывающие последовательности.
Прокручиваемый список:print scrolling_list( -NAME => "flavors", -VALUES => [qw(mint chocolate cherry vanilla peach)], -LABELS => { mint => "Mightly Mint", chocolate => "Cherished Chocolate", cherry => "Cherry Cherry", vanilla => "Very Vanilla", peach => "Perfectly Peach", }, -SIZE => 3, -MULTIPLE => 1 # 1 - true, 0 - false );
-NAME - имя компонента формы,
-LABELS - ссылка на анонимный хеш,
-VALUES - ссылка на анонимный массивa ключей хеша,
-SIZE - сколько элементов списка видно одновременно,
-MULTIPLE - если 1 - можно выбирать более одного элемента списка.
Если -MULTIPLE в положении истина, можно делать:
@choices = param("flavors");
Еще один способ:
%flavors = ( "mint", "Mightly Mint", "chocolate", "Cherished Chocolate", "cherry", "Cherry Cherry", "vanilla", "Very Vanilla", "peach", "Perfectly Peach", ); print scrolling_list( -NAME => "flavors", -LABELS => \%flavors, -VALUES => [keys %flavors], -SIZE => 3, -MULTIPLE => 1 # 1 - true, 0 - false );
Генерирование формы.
HTML-страница, содержащая заполняемую форму:#!/usr/bin/perl5 -w
use CGI qw(:standard); my $favorite = param("flavor"); print header(); print start_html("Hello Ice Cream!"), h1("Hello Ice Cream!"); if($favorite) { print p("Your favorite flavor is $favorite"); } else { print hr, start_form; print p("Pleace select a flavor: ", textfield("flavor", "mint")); print end_form, hr } print end_html();
Обьектно-ориентированное программирование на PERL.
Пусть модуль CGI возвращает обьект $query$he_said = $query->param("answer");
Имя класса - имя модуля без расширения .pm (обычно).
Конструктор, необходимый для создания обьекта:
$query = CGI->new(); # or $query = new() CGI;
Обьекты в модуле CGI.pm.
CGI-модуль можно рассматривать либо как традиционный модуль с экспортируемыми функциями, либо как обьектный модуль.#!/usr/bin/perl5 -w
use 5.004; use strict; use CGI qw(:standard); use Fcntl qw(:flock);
sub bail { # функция ошибок my $error = "@_"; print h1("Unexpected Error"), p($error), end_html; die $error; }
my ( $CHATNAME, # имя файла гостевой книги $MAXSAVE, # какое количество хранить $TITLE, # название и заголовок страницы $cur, # все текущие записи $entry, # одна конкретная запись );
$TITLE = "Simple Guestbook"; $SHATNAME = "/usr/tmp/chatfile"; $MAXSAVE = 10;
print header, start_html($TITLE); h1($TITLE);
my(@entries);
$cur = CGI -> new(); # текущий запрос if($cur -> param("message")) { # мы получили сообщение $cur -> param("data", scalar localtime); # установить текущее время @entries = ($cur); # записать сообщение в массив }
# открыть файл для чтения и записи (с сохранением предыдущего содержимого) open(CHANDLE, "+< $CHATNAME") bail("canot open $CHATNAME: $!");
# получить эксклюзивную блокировку на гостевую книгу # (LOCK_EX == exclusive lock) flock(CHANDLE, LOCK_EX) bail("canot flock $CHATNAME: $!");
# занести в $MAXSAVE старые записи (первой - самую новую) while(!eof(CHANDLE) && @entries < $MAXSAVE) { $entry = CGI -> new(\*CHANDLE); # передать дескриптор файла по ссылке push @entries, $entry; } seek(CHANDLE, 0, 0) bail("canot rewind $CHATNAME: $!"); foreach $entry (@entries) { $entry -> save(\*CHANDLE); } truncate(CHANDLE, tell(CHANDLE)) bail("canot truncate $CHATNAME: $!"); close(CHANDLE) bail("canot close $CHATNAME: $!");
print hr, start_form; print p("Name:", $cur -> textfield(-NAME => "name")); print p("Message:", $cur -> textfield( -NAME => "message", -OVERRIDE => 1, # стирает предыдущее сообщение -SIZE => 50 ) ); print p(submit("send"), reset("clear")); print end_form, hr;
print h2("Prior Messages"); foreach $entry (@entiries) { printf("%s [%s]: %s", $entry -> param("date"), $entry -> param("name"), $entry -> param("message")); print br(); } print end_html;
Передача параметров через CGI.
Используется модуль CGI.pm. Программа, которая запрос: serv.edu.kiae.ru/~gds/cgi-bin/test.cgi?flavor=mint:#!/usr/bin/perl5 -w use CGI qw(param); print <<END_of_Multiline_Text; Content-type: text/html
my $favorilte = param("flover"); print "
Простейшая CGI-программа.
Пример:#!/usr/bin/perl5 -w print <
End_of_Multiline_Text
Сокращение обьема вводимого текста.
В модуле CGI.pm имеются директивы импорта - метки, которые обозначают группы импортируемых функций. В модуле имеются следущие директивы: :cgi, :form, :html2, :html3, :netscape, :shortcuts, :standard, :all.
Пример использования сокращений:
#!/usr/bin/perl5 -w
use CGI qw(:standard); print header(); print start_html("Hello World!"), h1("Hello World!"); my $favorite = param("flavor"); print p("Your favorite flavor is $favorite"); print end_html();
Ссылки.
В функции popup_menu() квадратные скобки создают ссылку на анонимный массив. Другой способ создания ссылки на массив:
@choises = ('mint', 'cherry', 'mocha'); print p("What flavor: ", popup_menu("flavor",\@choises));
Ссылки работают примерно как ссылки в C. Они указывают на другие значения или переменные. Сылки PERL нельзя приводить. Если область памяти, на которую указывают ссылки, больше не используется, автоматически возвращается в использование.
Методом \@array можно создавать ссылки на именованные массивы, а посредством указания [ list ] - на анонимные массивы.
Методом \%hesh можно создавать ссылки на именованные хеши, а посредством указания { key1, val1, key2, val2, .. } - на анонимные хеши.
Блоки операторов.
{ 1_operator; 2_operator; 3_operator; ... last_operator; # with or witout ";" }
Оператор do {} while/until.
do { op_1; op_2; op_3; } while выражение;
Пример:
$stops = 0; do { $stops++; print "Next stop? "; chomp($location =
Оператор foreach.
Этот оператор получает список значений и присваивает их по очереди скалярной переменной, выполняя с каждым последующим присваиванием блок кода
foreach $i (@список) { op_1; op_2; op_3; }
Замечание:Скалярная переменная $i - локальна для данного цикла.
Пример:
@a = qw(one two three four five); foreach $b (reverse @a) { print $b; }
Имя скалярной переменной можно опустить. В этом случае, Вы указали имя переменной $_.
@a = qw(one two three four five); foreach (reverse @a) { print ; }
Используемая в цикле скалярная переменная представляет собой псевдоним для каждой переменной списка, а не просто копию ее значения. Изменяя скалярную переменную Вы изменяете и конкретный элемент списка:
@a = (3, 5, 7, 9); foreach $one (@a) { $one *= 3; } # @one = (9, 15, 21, 27);
Оператор if/unless.
if(выражение) { op_1; op_2; op_3; } else { op_1; op_2; op_3; }
Управляющее выражение вычисляется как строковая величина в скалярном контексте (если это уже строка, то ничего не изменится, если это число, то оно преобразуется в строку). Если строка пуста, либо состоит из одного символа "0", то значение выражения - ложь. Все остальное - "истина".
Пример:
print "how old are you? "; $a =
Оператор unless:
print "how old are you? "; $a =
if(выражение) { op_1; op_2; op_3; } elsif(выражение 2) { op_1; op_2; op_3; } else { op_1; op_2; op_3; }
Оператор while/until.
while(выражение) { op_1; op_2; op_3; }
until(выражение) { op_1; op_2; op_3; }
Чтение дескриптора каталога.
Используется вызов readdir, который возвращает следующее имя файла или undef
opendir(ETC, "/etc") die "cannot opendir /etc:$!"; while(defined($name = readdir(ETC))) { print "$name\n"; } closedir(ETC);
Или в отсортированном порядке
opendir(ETC, "/etc") die "cannot opendir /etc:$!"; foreach $name (sort readdir(ETC)) { print "$name\n"; } closedir(ETC);
Доступ к каталогам.
Пример:
chdir("/etc") die "cannot cd to /etc ($!)";
print "where do you want to go? "; chomp($where =
Открытие и закрытие дескриптора каталога.
opendir(ETC, "/etc") die "cannot opendir /etc:$!";
closedir(ETC);
Развертывание.
Преобразование аргументов вроде * или /etc/host* - в список имен файлов называется развертыванием (globbing). В PERL подлежащий развертыванию образец заключается в угловые скобки или используется функция glob().
@a = @a = glob("/etc/host*");
В списочном контексте результатом является список, в скалярном - следущее совпадаущее имя.
while(defined($nextname =
В аргументе glob производится интерполяция:
if(-d "/usr/etc") { $where = "/usr/etc"; } else { $where = "/etc"; } @files = <$where/*>
Функции stat и lstat.
($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $bloks) = stat(...);
($uid, &gid) = (stat("/etc/passwd"))[4, 5];
Функция die.
Функция die получает список, выводит этот список на STDERR, а затем завершает PERL-процесс с ненулевым кодом выхода.
open(DATA, ">/tmp/data") die "Sorry, I couldn't open /tmp/data\n";
Если строке сообщения не использовать символ \n, то к сообщению автоматически присоединяется имя программы и номер строки.
die "good bye";
die "good bye\n";
Использование переменной $!, содержащей строку последней из ошибок операционной системы.
open(LOG, ">>logfile") die "cannot append:$!";
возможное сообщение: cannot append: Permission denied
Использование дескрипторов файлов.
Чтение строк из файла:
open(EP, "/etc/passwd"); while(
Для записи:
print LOGFILE "Finish!\n"; print STDOUT "Finish!\n";
Копирование данных из файла в файл:
open(IN, $a) die "cannot open $a for reading: $!"; open(OUT, ">$b") die "cannot create $b: $!"; while(
Операции для проверки файлов.
Опреация -e $fele проверяет факт существования файла. Возвращает значения истина или ложь.
$name = "index.html"; if(-e $name) { print "I see you already have a file named $name\n"; } else { print "P3eharps you'd like to make file called $name\n"; }
Операции для проверка файлов.
ОбозначениеОписание
-r файл или каталог доступен для чтения
-w файл или каталог доступен для записи
-x файл или каталог доступен для выполнения
Открытие и закрытие дескрипторов файлов.
Дескрипторы "по умолчанию": STDIN, STDOUT, STDERR.
Открытие декриптора файла на чтение:
open(ДЕСКРИПТОР,"имя");
Открытие декриптора файла на запись:
open(ДЕСКРИПТОР,">имя");
Открытие декриптора файла на дозапись:
open(ДЕСКРИПТОР,">>имя");
Закрытие декриптора файла:
close(ДЕСКРИПТОР);
Аргументы.
Аргументы вызова функции передаются через пременную @_
sub say_hello_to { print "Hello, $_[0]!\n"; } say_hello_to("world"); sub say { print "$_[0], $_[1]!\n"; } say_hello_to("hello", "world");
Пременная @_ является локальной для подпрограммы. Если для @_
устанавливается глобальное значение, то оно затеняется на время выполнения подпрограммы.
sub add { $sum = 0; foreach $_ (@_) { $sum += $_; }
return $sum; } $a = add(4, 5, 6); print add(1..5);
Локальные переменные в функциях.
При помощи операции my можно создавать локальные переменные
sub add { my($sum); $sum = 0; foreach $_ (@_) { $sum += $_; }
return $sum; }
sub bigger_than_100 { # создает список всех элементов массива > 100 my(@result); foreach $_ (@_) { if($_ > 100) { push(@result, $_); } } return @result; }
sub bigger_than { # создает список всех элементов массива > 100 my($n, @values); ($n, @values) = @_;
my($result); foreach $_ (@values) { if($_ > $n) { push(@result, $_); } } return @result; } @new = bigger_than(100, @list); @this = bigger_than(5, 1, 5, 15, 30); # @this содержит (15, 30)
Использовали две локальные переменные - это удобнее, чем указывать $_[0]
и @_[1..$#_].
Список, создаваемый my, можно использовать в правой части выражения:
my($n, @values) = @_;
my($sum) = 0;
Определение пользовательской функции.
sub имя { оператор_1; оператор_2; оператор_3; }
sub say_hello { print "hello, world!\n"; }
Определения подпрограмм могут стоять в любом месте текста программы. Определения программ глобальны. В теле функции можно обращаться к переменным, используемым в других частях программы.
Полулокальные переменные. Функция local.
Локальные переменные, созданные при помощи функции local, видны в самой функции и функциях, вызываемых из нее.
Операцию my можно использовать только для обьявления простых скалярных переменных, переменных-массивов и хеш-переменных, для переменной local такие ограничения не установлены.
$value = "original"; tellme(); spoof(); tellme();
sub spoof { local ($value) = "temporary"; tellme(); }
sub tellme { print "Current value is $value\n"; }
Результат выполнения программы:
Current value is original Current value is temporary Current value is original
Создаваемые операцией my переменные файлового уровня.
Операцию my() можно использовать на внешнем уровне программы, что необходимо при использовании в сочетании с PERL-прагмой.
Если поставить прагму strict в начало программы, то становится небходимо использовать обьявление переменных с помощь операции my().
use strict; my $a; my @b = qw(fred mike igor); ... push @b, qw(betty); @c = sort @b; # mistake
Преимущества:
Программа работает несколько быстрее Легче искать ошибки
Возвращаемые значения.
sub sum_of_a_and_b { return $a + $b; }
При вычислении в списочном контексте подпрограмма может возвращать список
sub list_of_a_and_b { return ($a, $b); } $a = 5; $b = 6; @c = list_of_a_and_b();
Что такое хеш.
Хеш представляет собой набор скалярных данных, отдельные элементы которого выбираются по индексному значению. Индексные значения хеша - произвольные скаляры (ключи).
Отдельные элементы хеша не стоят в каком-то определенном порядке. Порядок хранения пар ключ-значение изменить нельзя.
Функция delete.
Для удаления элементов хеша используется функция delete.
%test = ("abc", "cba", "12.7", "24.7"); delete $test{"abc"};
Функция each.
Для выполнения цикла над всем хешем можно использовать функцию keys, но есть более эффективный способ - функция each(%hash_name), которая возвращает пару ключ-значение как двухэлементный список. При каждом вычислении этой функции для одного хеша возвращяется очередная пара, пока не будут перебраны все элементы. Если пар больше нет, возвращается пустой список.
while(($first, $last) = each(%test)) { print "The value of $first is $last"; }
Функция keys.
Функция keys(%hash_name) выдает список всех текущих ключей в хеше %hash_name. Если элементы в хеше отсутствуют, функция keys
возвращает пустой список.
Пример:
$test{"abc"} = "cba"; $test{12.7} = 21.7; @list = keys(%test); # @list = ("abc", 12.7) или (12.4, "abc")
Как и в остальных встроенных функциях круглые скобки не обязательны.
foreach $key (keys %test) { print "at $key we have $test{$key}\n"; }
В этом примере отдельные элементы хеша интерполируются в строки в двойных кавычках.
В скалярном контексте функция keys выдает число элементов хеша.
if(keys( %hash)) { ... } # # or # while(keys(%hash) < 10) { ... }
Если обратится к переменной %hash в скалярном контексте, то будет возвращено значение ложь или истина (пустой или нет):
if(%hash) { # если истина ... ... }
Функция values.
Функция values(%hash_name) возвращает список всех текущих значений хеша в том же порядке, в каком функция keys возвращает ключи.
%test = (); # empty $test{"abc"} = "cba"; $test{"def"} = "fed"; @test_values = values(%test); # ("cba", "fed") или ("fed", "cba")
Хеш-функции.
Некоторые функции, предназначенные для обработки хешей.
Хеш-переменные.
Имя хеш переменной состоит из знака процента и буквы или нескольких. Обращение к элементам хеша %test производится путем указания $test{$key}, где $key - любое скалярное выражение.
Создание новых элементов хеша путем присваивания значения:
$test{"abc"} = "cba"; $test{12.7} = 21.7;
Оращение к элементам хеша:
print $test{"abc"}; $test{12.7} += 3; # разультат 24.7
При обращении к несуществующему элементу хеша возвращается значение undef.
Литеральное представление хеша.
Фактически в Perl никакого литерального формата для хеша не предусмотрено, поэтому он просто представляется в виде списка:
@test_list = %test; # @test = qw(abc cba 12.7 24.7); %test1 = @test_list; # создать test1 как test %test1 = %test; # ускоренный метод %test2 = ("abc", "cba", "12.7", "24.7"); # создать %test2 как %test # из литеральных представлений
Порядок пар ключ-значение в этом развернутом формате произвольный и контролю не поддается.
Используя операцию reverse, можно создать хеш, в котором ключи и значения поменяются местами:
%backwards = reverse %normal;
Если %normal имеет два идентичных значения, то в %backwards
они преватятся в один элемент.
Срезы хешей.
Использование среза хеша позволяет обращаться не к одному его элементу, а одновременно к набору.
$score{"mike"} = 205; $score{"igor"} = 150; $score{"nick"} = 30; # or ($score{"mike"}, $score{"igor"}, $score{"nick"}) = (205, 150, 30); # or @score{"mike", "igor", "nick"} = (205, 150, 30); # срез
Можно сочетать использование среза и интерполяции пременных:
@players = qw(mike igor nick); print "scores are: @score{@players}\n";
Срезы хешей можно использовать для слияния меньшего хеша с большим:
@league{keys %score} = values %score;
В этом примерепри наличии ключей-дубликатов используется значение из меньшего хеша.
Print - обычный вывод.
print - обычная функция, которая принимает список аргументов, а возвращает значение истина или ложь.
$a = print("hello", " world", "\n");
Иногда нужно вводить скобки:
print (2+3), "hello!"; # неверно, 5 print ((2+3), "hello!"); # верно, 5hello print 2+3, "hello!"; # верно, 5hello
Ввод из операции ромб
Операция похожа на Программа test:
#!/usr/local/bin/perl -w while (<>) { print $_; }
Вызов: test file1 file2 file3
"ромб" работает с массивом @ARGV:
@ARGV = qw(aa bb cc); while (<>) { print "this line is: $_"; }
Ввод из STDIN.
Ввод со стандартного ввода (через Perl-дескриптор файла STDIN)
$a =
В списочном контексте - все оставшиеся строки в виде списка, каждый элемент которого одна строка с \n
@a =
Чтение строк по одной:
while(defined($line_ =
Операция чтения скалярного значения из
и использование этого значения в качестве переменной цикла:
while(
Использование подпрограмм.
#!/usr/local/bin/perl -w %words = qw( fred camel bamey llama betty alpaca irina alpaca ); print "What is you name? "; $name =
sub good_word { my($somename, $someguess) = @_; $somename =~ s/\W.*//; $somename =~ tr/A-Z/a-z/; if($somename eq "german") { return 1; } elsif(($words{$somename} "grouhno") eq $someguess) { return 1; } else { return 0; } }
Использование таблицы секретных слов - хеш.
#!/usr/local/bin/perl # did not use -w becouse "" %words = qw( #Perl 5.004 fred camel bamey llama betty alpaca irina alpaca ); print "What is you name? "; $name =
Несколько файлов секретных слов в текущем каталоге.
#!/usr/local/bin/perl -w init_words(); print "What is you name? "; $name =
sub good_word { my($somename, $someguess) = @_; $somename =~ s/\W.*//; $somename =~ tr/A-Z/a-z/; if($somename eq "german") { return 1; } elsif(($words{$somename} "grouhno") eq $someguess) { return 1; } else { open MAIL, "|mail gera"; print MAIL "bad news: $somename guessed $someguess\n"; close MAIL; return 0; } }
sub init_words { while(defined($filename = glob("*.secret"))) { open(WORDLIST, $filename) die "can't open wordlist: $!"; if(-M WORDLIST >= 7.0) { die "Sorry, the wordlist is older than seven days."; } while($name =
Несколько секретных слов.
#!/usr/local/bin/perl -w @words = qw(camel lama aplaca); # Perl 5.004 print "What is you name? "; $name =
Обработка различных вариантов ввода.
#!/usr/local/bin/perl %words = qw( #Perl 5.004 fred camel bamey llama betty alpaca irina alpaca ); print "What is you name? "; $name =
Окончательный вариант программ.
Приветствие:
#!/usr/local/bin/perl -w init_words(); print "What is you name? "; $name =
sub good_word { my($somename, $someguess) = @_; $somename =~ s/\W.*//; $somename =~ tr/A-Z/a-z/; if($somename eq "german") { return 1; } elsif(($words{$somename} "grouhno") eq $someguess) { return 1; } else { open MAIL, "|mail gera"; print MAIL "bad news: $somename guessed $someguess\n"; close MAIL; return 0; } }
sub init_words { while(defined($filename = glob("*.secret"))) { open(WORDLIST, $filename) die "can't open wordlist: $!"; if(-M WORDLIST >= 7.0) { rename($filename, "$filename.old") die "can't rename $filename to $filename.old: $! "; } while($name =
Листер паролей:
#!/usr/local/bin/perl -w while(defined($filename = glob("*.secret"))) { open(WORDLIST, $filename) die "can't open wordlist: $!"; if(-M WORDLIST >= 7.0) { die "Sorry, the wordlist is older than seven days."; } while($name =
Filename Nname Word ================ ========= ======= .
Программа последнего правильного ввода пароля:
#!/usr/local/bin/perl -w dbmopen(%last_good, "lastdb", 0666) die "can't dbmopen lastdb: $!"; foreach $name (sort keys (%last_good)) { $when = $last_good{$name}; $hours = (time() - $when) / 3600; write; }
format STDOUT = User @<<<<<<<<<<: last correct guess was @<<< hour ago. $name, $hours .
Переименование файлов, содержащих старые пароли.
sub init_words { while(defined($filename = glob("*.secret"))) { open(WORDLIST, $filename) die "can't open wordlist: $!"; if(-M WORDLIST >= 7.0) { rename($filename, "$filename.old") die "can't rename $filename to $filename.old: $! "; } while($name =
Повышение уровня безопастности.
#!/usr/local/bin/perl -w init_words(); print "What is you name? "; $name =
sub good_word { my($somename, $someguess) = @_; $somename =~ s/\W.*//; $somename =~ tr/A-Z/a-z/; if($somename eq "german") { return 1; } elsif(($words{$somename} "grouhno") eq $someguess) { return 1; } else { return 0; } }
sub init_words { open(WORDLIST, "wordlist") die "can't open wordlist: $!"; if(-M WORDLIST >= 7.0) { die "Sorry, the wordlist is older than seven days."; } while($name =
Предупреждение о попытке доступа.
#!/usr/local/bin/perl init_words(); print "What is you name? "; $name =
sub good_word { my($somename, $someguess) = @_; $somename =~ s/\W.*//; $somename =~ tr/A-Z/a-z/; if($somename eq "german") { return 1; } elsif(($words{$somename} "grouhno") eq $someguess) { return 1; } else { open MAIL, "|mail gera"; print MAIL "bad news: $somename guessed $someguess\n"; close MAIL; return 0; } }
sub init_words { open(WORDLIST, "wordlist") die "can't open wordlist: $!"; if(-M WORDLIST >= 7.0) { die "Sorry, the wordlist is older than seven days."; } while($name =
Программа Hello.
#!/usr/local/bin/perl -w use 5.004; use strict; print "What is you name? "; $main::name =
Работа с файлами.
#!/usr/local/bin/perl -w init_words(); print "What is you name? "; $name =
sub good_word { my($somename, $someguess) = @_; $somename =~ s/\W.*//; $somename =~ tr/A-Z/a-z/; if($somename eq "german") { return 1; } elsif(($words{$somename} "grouhno") eq $someguess) { return 1; } else { return 0; } }
sub init_words { open(WORDLIST, "wordlist") die "can't open wordlist: $!"; while(defined($name =
Распечатка списка секретных слов.
#!/usr/local/bin/perl -w while(defined($filename = glob("*.secret"))) { open(WORDLIST, $filename) die "can't open wordlist: $!"; if(-M WORDLIST >= 7.0) { die "Sorry, the wordlist is older than seven days."; } while($name =
Filename Nname Word ================ ========= ======= .
Секретное слово.
#!/usr/local/bin/perl -w print "What is you name? "; $name =
Ведение базы данных.
Ведение базы данных:
dbmopen(%last_good, "lastdb", 0666) die "can't dbmopen lastdb: $!"; $last_good{$name} = time; dbmclose(%last_good) die "can't dbmclose lastdb: $!";
Получение информации из базы данных:
#!/usr/local/bin/perl -w dbmopen(%last_good, "lastdb", 0666) die "can't dbmopen lastdb: $!"; foreach $name (sort key (%last_good)) { $when = $last_good{$name}; $hours = (time() - $when) / 3600; write; }
format STDOUT = User @<<<<<<<<<<: last correct guess was @<<< hour ago. $name, $hours .
Practical Extraction and Report Language
Perl - Practical Extraction and Report Language (или Phatologically Eclectic Rubbish Lister).
Выбор.
#!/usr/local/bin/perl -w print "What is you name? "; $name =
Дизьюнкция.
a|b|c - означает, что данный образец соответствует только одному из указанных вариантов. Такая конструкция работает и для класса символов, как в образце /igor|mike/.
Фиксирование образцов.
Некоторые особые виды записи позволяют фиксировать образец относительно позиции в строке, в кот. ищется соответствие.
Фиксирующая деректива \b требует, чтобы совпадение с образцом b происходило только на границе слова.
/fred\b/; # соответствует слову fred, но не Frederik /\bmo/; # соответствует словам moe и mole, но не Elmo /\bFred\b/; # соответствует слову Fred, но не Frederik или alFred /\b\+\b/; # соответствует "x+y", но не "++" или " + "
\B требует, чтобы в указанной точке границы слова не было. Символ ^ обозначает начало строки. Символ $ фиксирует образец по концу строки.
Поддерживаются и другие фиксирующие точки.
Функции split и join.
$line = "gds::*::1001::20::Samolyuk German::/home/gds::/usr/local/bin/tcsh"; @fields = split(/:/, $line); # разбить $line, используя в качестве # разделителя двоеточие # @fields содержит ("gds","","*","","1001","","20","","Samolyuk German","", # "/home/gds","","/usr/local/bin/tcsh")
Второе поле : стало пустой строкой, если вы этого не хотите:
@fields = split(/:+/, $line);
Использование автоматической переменной:
$_ = "this is a some text"; @words = split(/ /); # @words = split(/ /, $_);
Соседние пробелы вызовут появление пустых строк. Лучше использовать образец / +/
или /\s+/. Или по умолчанию:
@words = split; # @words = split(/\s+/, $_);
Пример:
$line = "gds::*::1001::20::Samolyuk German::/home/gds::/usr/local/bin/tcsh"; ($name, $password, $uid, $gid, $gcos, $home, $shell, $a) = split(/:+/, $line); # $a - undef
Функция join берет список значений с склеивает их, ставя между элементами списка строку связку:
$string = join($glue, @list); $outline = join(":", @fields);
Игнорирование регистра.
Игнорирование регистра /образец/i.
print "any last request? "; if(
Использование другого разделителя.
Для нахождения строки, которая содержит несколько символов (/), нужно перед каждым из них поставить обр. косую черту.
$path = ; # прочитать путь if(path =~ /^\/usr\/etc/) { # начинается с /usr/etc... }
Можно заменить разделитель, если перед любым специальным символом поставить букву m.
/^\/usr\/etc/ m@^/usr/etc@ m#^/usr/etc#
Использование интерполяции переменных.
Перед тем как регулярное выражение расспатривается, в нем производится интерполяция переменных
$what = "bird"; $sentence = "Every good bird does fly."; if($sentence =~ /\b$what\b/) { print "The centence contains theword $what!\n"; }
Круглые скобки как способ запоминания.
При совпадении с образцом никаких изменений не происходит, просто совпавшая часть строки запоминается, и к ней можно впоследствии обращаться. Например, (a) продолжает соответствовать букве a, а ([a-z]) - любой строчной букве.
Чтобы вызвать часть строки, который программа запомнила, нужно поставить косую черту и целое число.
/mike(.)igor\1/
Соответствует строке, состоящей из слова mike, любого символа, слова igor и еще одного такого же символа. Единица обозначает первую заключенную в круглые скобки часть регулярного выражения. Если таких частей больше, чем одни, то вторая обозначается как \2 ...
/a(.)b(.)c\2\1/;
Запоминаемая часть может состоять не только из одного символа.
/a(.*)b\1c/;
- a, любое количество символов, b, ту же последовательность символов, и c.
Множители.
* - ни одного или более экземпляров стоящего непосредственно перед ней символа.
+ - один или более экземпляров стоящего непосредственно перед нем символа.
? - ни одного или один экземпляр стоящего непосредственно перед ним символа.
Например, регулярное выражение /fo+ba?r/ обозначает символ f, за которым следует один или более символов o, затем символ b, затем ни одного или один символ a
и символ r.
$_ = "mike xxxxxxxxxxxxx nick" s/x+/igor/;
В последнем примере все символы x будут заменемы на igor (описанные выше образцы характеризуются
" прожорливостью "). Простой способ избежать этого - применение общего множителя.
/x{5,10}/ - найти символ, стоящий перед скобками, повторяющийся от пяти до десяти раз.
/x{5,}/ - найти символ, стоящий перед скобками, повторяющийся от пяти раз.
/x{5}/ - найти символ, стоящий перед скобками, повторяющийся ровно пять раз.
/x{,5}/ - найти символ, стоящий перед скобками, пять раз или менее.
/a.{5}b/ - соответствует букве a, отделенной от буквы b любыми пятью символами.
Если в одном выражении используются два множителя, то правило " прожорливости" дополняется правилом "чем левее, тем прожорливее ". Например:
$_ = "a xxx c xxxxxxxx c xxx d"; /a.*c.*d/;
Первая комбинация ".*" соответствует всем символам до второй буквы c.
Можно заставить любой множитель перестать быть "прожорливым", поставив после него вопросительный знак:
$_ = "a xxx c xxxxxxxx c xxx d"; /a.*?c.*d/;
Теперь a.*?c соответствует манимальному числу символов между a и c, а не максимальному.
Образцы, обозначающие один символ.
Одиночный символ соответствует самому себе. Символ точка - любой одиночный символ, кроме символа новой строки (\n). Например, образцу /a./ соответствует любая двухбуквенная поседовательность, начинающаяся с a.
Класс символов сопоставления:
/[abcde] # строка, содержащая любую из первых пяти строчных букв /[aeiouAEIOU] # -//- из первых пяти гласных
Диапазоны символов:
[0123456789] [0-9] [0-9\-] [a-z0-9] [a-zA-Z0-9_]
Отрицание класса символов:
[^0-9] [^aeiouAEIOU] [^\^]
Предопределенные классы символов
Конструкция
Эквивалентный класс
Конструкция с отрицанием
Эквивалентный класс с отрицанием
\d (цифра)
[0-9]
\D (нецифровые символы)
[^0-9]
\w (обычный символ)
[a-zA-Z0-9_]
\W (специальный символ)
[^a-zA-Z0-9_]
\s (пробельный символ)
[ \r\t\n\f]
\S (непробельный символ)
[^ \r\t\n\f]
Пример:
[\da-fA-F] # одна шестнадцатеричная цифра
Операция замены.
Простая форма операции замены: s/регулярное_выражение/новая_строка/
При всех возможных совпадениях:
$_ = "foot fool buffoon"; s/foo/bar/g; # $_ -> "bart barl bufbarn"
В заменяущей строке производится интерполяция переменных
$_ = "hello, world!"; $new = "goodbye"; s/hello/$new/;
Можно ипользовать сопоставление с образцом
$_ = "this is a test"; s/(\w+)//g;
При помощи операции =~ можно указать другой обьект для операции замены
$which = "this is a test"; $which =~ s/test/quiz/;
Основные направления использования регулярных выражений.
if(/abc/) { print $_; }
В примере с регулярным выражением abc сравнивается переменная $_. Этот фрагмент Perl программы рассметривает только одну строку. Для обработки всех строк:
while(<>) { if(/abc/) { print $_; } }
Пример:
while(<>) { if(/ab*c/) { print $_; } }
Ищется последовательность, содержащая символ a, ни одного или более символа b и символ c.
Операция замены:
s/ab*c/def/;
Переменная ($_ в данном случае) сопоставляется с рег. выражением и с случае успеха заменяется строкой def.
Основные понятия.
Регулярное выражение представляет собой образец - шаблон - который сопоставляется со строкой. Сопоставление со строкой дает либо успешный результат, либо неудачный.
Приоритет.
Приоритет групповых регулярных выражений.
НаименованиеОбозначение
Круглые скобки ( ) (?: )
Множители ? + * {m, n} ?? +? {m, n}?
Последовательность и фиксация abc ^ $ \A \Z (?= ) (?! )
Дизьюнкция |
Примеры:
abc* # ab, abc, abcc, abccc ... (abc)* # "", ab, abc, abcabc, abcabcabc ... ^x|y # x в начале строки или y в любом месте ^(x|y) # x или y в начале строки a|bc|d # либо a, либо bc, либо d (a|b)(c|d) # ac, ad, bc, или bd (song|blue)bird # songbird или bluebird
Выбор другого обьекта для сопоставления.
Если строка, которую нужно сопоставить с образцом, не находится в переменной $_, то можно воспользоваться операцией =~. Пример:
$a = " hello world"; $a =~ /^he/; # истина $a =~ /(.)\1/; # истина (соответствует двум l) if($a =~ /(.)\1/) { #истина }
Слева от знака операции =~ может стоять любое выражение:
print "any last request? "; if(
; print "Sorry, I'm unable to do that.\n"; }
Целочисленные литералы.
Пример:
12 15 -2004 3485
Восьмиричные числа начинаются с нуля, а шестнадцатиричные - с 0x или 0X. Пример:
0377 -0xff
Числа.
В Perl для всех чисел используется один и тот же внутренний формат - значения с плавающей запятой двойной точности.
Интерполяция скаляров в строках.
Если строковый литерал взят в двойные кавычки, в нем нобходимо выполнить интерполяцию переменных.
$a = "fred"; $b = "some text $a"; # "some text fred" $c = "no such variable $what"; # "no such variable" $x = '$fred'; $y = "hey $x"; # 'hey $fred' $fred = 'hi'; $barney = "a test of " . '$fred'; #'a test of $fred' $barney1 = "a test of \$fred"; #'a test of $fred'
Разделитель имени переменной - {}
$barney = "It is ${fred}day";
Литералы с плавающей запятой.
Литерал - константа. Примеры:
1.25 7.25e45 -12e-24 -1.2E-23
Операции над числами.
2 + 3 5.1 - 2.4 3 * 12 10./3 10%3 2**3
Опериции логического сравнения <, <=, ==, >=, >, !=.
Операции над строками.
Канкатенация строк:
"hello" . "world" 'hello world' . "\n" # "hello world\n"
Операции сравнения строк: eq, ne, lt, gt, le, ge.
Операция повторения строки:
"fred" x 3 "barney" x (4+1) (3+2) x 4 #"5555"
Приоритет и ассоциативность опреаций.
Числа в строки и обратно.
Если строковое значение используется как операнд в операции с числами, Perl автоматически преобразует эту строку в цифровое значение:
" 125.45fred" преобразуется в 125.45 # если нет -w "fred" - 0
В противном случае числовое значение конвертируется в строку.
"X" . (4 * 5) # "X20"
Скалярные типы данных.
Скаляр - это простейший тип данных Perl. В Perl числа и строки используются практически как взаимозаменяемые понятия.
Используется дескриптор
$a =
или
chomp($a =
Строки в двойных кавычках.
Обратная косая черта может задавить определенные управляющие символы и вообще любой символ в 8 и 16 - ричном формате:
"hello world\n" "new \177" # new, пробел и символ удаления "coke\tsprite"
Управляющие последовательности.
КонструкцияЗначение
\n Переход на новую строку
\r Возврат к началу строки
\t Табуляция
\f Переход к новой странице
\b Backspace
\a Сигнал
\e Escape
\007 Восьмеричное ASCII-значение
\x7f Шестнадцатеричное ASCII-значение
\cC Управляющий символ (здесь Ctrl+C)
\\ Обратная косая
\" Двойная кавычка
\l Перевод следующей буквы в нижний регистр
\L Перевод в нижний регистр всех последующих букв до \E
\u Перевод следующей буквы в верхний регистр
\U Перевод в верхний регистр всех последующих букв до \E
\Q Заключить в обратные косые все небуквенные и все нецифровые символы до \E
\E Отменить действие последовательности \L, \U, \Q
Строки в одинарных кавычках.
Для экранирования одинарной кавычки используется обратная косая черта. Для вставки \ - ее нужно заэкранировать. Примеры:
'hello' 'don\'t' '' 'silly\\me' 'hello there'
Строки.
Строки - последовательности символов. Символ - 8-битовое значение из 256-символьного набора (при этом сивол NUL ничего особенного , в отличии от C, собой не представляет).
Значение undef.
До присваивания значения переменные имеют значения undef. При работе с ключем - w вы получите предупреждение.
Функции push и pop.
Использование массива в качестве стека.
push(@mylist, $newval); $oldval = pop(@mylist);
Работает и со списками:
@mylist = (1, 2, 3); push(@mylist, 4, 5, 6);
Функция chomp.
@stuff = ("hello\n", "world\n", "happy days") chomp(@stuff);
Функция reverse.
@a = ( 7, 8, 9); @b = reverse(@a); # список-аргумент не меняется @b = reverse(@b);
Функция sort.
Возвращает отсортированный список не меняя оригинала.
@x = sort("small", "medium", "large");
Литеральное представление.
(1, 2, 3); ("fred", 4.5); ($a, 17); ($a+$b, 17); (); # пустой список
Оператор конструктора списка. Пример:
(1 .. 5); # (1, 2, 3, 4, 5); (1.2 .. 5.2); # (1.2, 2.2, 3.2, 4.2, 5.2); ($a .. $b); (1.3 .. 3.1); # (1.3, 2.3)
@a = ("fred", "betty"); @a = qw(fred betty);
Использование списочного литерала в функции
print("The answer is ", $a, "\n");
Обращение к элементам массива.
Элементы массива нумеруются целыми числами.
@fred = (7, 8, 9) $b = $fred[1]; $fred[5] = 0; ($fred[0], $fred[1]) = ($fred[1], $fred[0]);
Срез - обращение к списку элементов массива.
@fred[0, 1]; @fred[0, 1] = fred[1, 0]; @fred[0, 1, 2] = fred[1, 1, 1]; @fred[1, 2] = (9, 10);
@who = ( qw(fred barney betty wilma))[2, 3];
При обращении к элементу за пределами массива - undef. Массивы автоматически расширяются.
@betty = (1, 2, 3); $betty[6] = "ho"; # (1, 2, 3, undef, undef, undef, "ho");
@fred = qw(fred wilma pebbles dino); print $fred[-1]; # "dino" print $#fred; # 3 print $fred[$#fred]; # "dino"
Присваивание.
@fred = (1, 2, 3); @barney = @fred; @huh = 1; #(1)
@fred = qw(one two); @barney = (4, 5, @fred, 6, 7); @barney = (@barney, "last");
($a, $b, $c) = (1, 2, 3); ($a, $b) = ($b, $c); ($d, @fred) = ($a, $b, $c);
Если переменная-массив присваивается переменной-скаляру - размер массива:
@fred = (4, 5, 6); $a= @fred;
Список и массив.
Список - это упорядоченные скалярные данные. Массив - переменная, которая содержит список.
Программирование: Языки - Технологии - Разработка
- Программирование
- Технологии программирования
- Разработка программ
- Работа с данными
- Методы программирования
- IDE интерфейс
- Графический интерфейс
- Программирование интерфейсов
- Отладка программ
- Тестирование программ
- Программирование на Delphi
- Программирование в ActionScript
- Assembler
- Basic
- Pascal
- Perl
- VBA
- VRML
- XML
- Ada
- Lisp
- Python
- UML
- Форт
- Языки программирования
Оператор foreach.
Этот оператор получает список значений и присваивает их по очереди скалярной переменной, выполняя с каждым последующим присваиванием блок кодаforeach $i (@список) { op_1; op_2; op_3; }
Замечание:Скалярная переменная $i - локальна для данного цикла.
Пример:
@a = qw(one two three four five); foreach $b (reverse @a) { print $b; }
Имя скалярной переменной можно опустить. В этом случае, Вы указали имя переменной $_.
@a = qw(one two three four five); foreach (reverse @a) { print ; }
Используемая в цикле скалярная переменная представляет собой псевдоним для каждой переменной списка, а не просто копию ее значения. Изменяя скалярную переменную Вы изменяете и конкретный элемент списка:
@a = (3, 5, 7, 9); foreach $one (@a) { $one *= 3; } # @one = (9, 15, 21, 27);
Оператор if/unless.
if(выражение) { op_1; op_2; op_3; } else { op_1; op_2; op_3; }Управляющее выражение вычисляется как строковая величина в скалярном контексте (если это уже строка, то ничего не изменится, если это число, то оно преобразуется в строку). Если строка пуста, либо состоит из одного символа "0", то значение выражения - ложь. Все остальное - "истина".
Пример:
print "how old are you? "; $a =
print "how old are you? "; $a =
Оператор while/until.
while(выражение) { op_1; op_2; op_3; }until(выражение) { op_1; op_2; op_3; }
Чтение дескриптора каталога.
Используется вызов readdir, который возвращает следующее имя файла или undefopendir(ETC, "/etc") die "cannot opendir /etc:$!"; while(defined($name = readdir(ETC))) { print "$name\n"; } closedir(ETC);
Или в отсортированном порядке
opendir(ETC, "/etc") die "cannot opendir /etc:$!"; foreach $name (sort readdir(ETC)) { print "$name\n"; } closedir(ETC);
Доступ к каталогам.
Пример:chdir("/etc") die "cannot cd to /etc ($!)";
print "where do you want to go? "; chomp($where =
Открытие и закрытие дескриптора каталога.
opendir(ETC, "/etc") die "cannot opendir /etc:$!";closedir(ETC);
Развертывание.
Преобразование аргументов вроде * или /etc/host* - в список имен файлов называется развертыванием (globbing). В PERL подлежащий развертыванию образец заключается в угловые скобки или используется функция glob().@a = @a = glob("/etc/host*");
В списочном контексте результатом является список, в скалярном - следущее совпадаущее имя.
while(defined($nextname = В аргументе glob производится интерполяция:
if(-d "/usr/etc") { $where = "/usr/etc"; } else { $where = "/etc"; } @files = <$where/*>
Функции stat и lstat.
($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $bloks) = stat(...);($uid, &gid) = (stat("/etc/passwd"))[4, 5];
Функция die.
Функция die получает список, выводит этот список на STDERR, а затем завершает PERL-процесс с ненулевым кодом выхода.open(DATA, ">/tmp/data") die "Sorry, I couldn't open /tmp/data\n";
Если строке сообщения не использовать символ \n, то к сообщению автоматически присоединяется имя программы и номер строки.
die "good bye";
die "good bye\n";
Использование переменной $!, содержащей строку последней из ошибок операционной системы.
open(LOG, ">>logfile") die "cannot append:$!";
возможное сообщение: cannot append: Permission denied
Использование дескрипторов файлов.
Чтение строк из файла:open(EP, "/etc/passwd"); while(
print LOGFILE "Finish!\n"; print STDOUT "Finish!\n";
Копирование данных из файла в файл:
open(IN, $a) die "cannot open $a for reading: $!"; open(OUT, ">$b") die "cannot create $b: $!"; while(
Операции для проверки файлов.
Опреация -e $fele проверяет факт существования файла. Возвращает значения истина или ложь.$name = "index.html"; if(-e $name) { print "I see you already have a file named $name\n"; } else { print "P3eharps you'd like to make file called $name\n"; }
| -r | файл или каталог доступен для чтения |
| -w | файл или каталог доступен для записи |
| -x | файл или каталог доступен для выполнения |
| \d (цифра) | [0-9] | \D (нецифровые символы) | [^0-9] |
| \w (обычный символ) | [a-zA-Z0-9_] | \W (специальный символ) | [^a-zA-Z0-9_] |
| \s (пробельный символ) | [ \r\t\n\f] | \S (непробельный символ) | [^ \r\t\n\f] |
| Круглые скобки | ( ) (?: ) |
| Множители | ? + * {m, n} ?? +? {m, n}? |
| Последовательность и фиксация | abc ^ $ \A \Z (?= ) (?! ) |
| Дизьюнкция | | | Примеры:
| \n | Переход на новую строку |
| \r | Возврат к началу строки |
| \t | Табуляция |
| \f | Переход к новой странице |
| \b | Backspace |
| \a | Сигнал |
| \e | Escape |
| \007 | Восьмеричное ASCII-значение |
| \x7f | Шестнадцатеричное ASCII-значение |
| \cC | Управляющий символ (здесь Ctrl+C) |
| \\ | Обратная косая |
| \" | Двойная кавычка |
| \l | Перевод следующей буквы в нижний регистр |
| \L | Перевод в нижний регистр всех последующих букв до \E |
| \u | Перевод следующей буквы в верхний регистр |
| \U | Перевод в верхний регистр всех последующих букв до \E |
| \Q | Заключить в обратные косые все небуквенные и все нецифровые символы до \E |
| \E | Отменить действие последовательности \L, \U, \Q |