В этой части речь пойдет об условных операторах и циклах.

Условные операторы

Как всегда, начнем сразу с примеров.

$a = shift ;
if ($a > 10 ) {
print "a > 10\n " ;
}

Программистам на C-подобных языках эта конструкция должна быть до боли знакома, так что комментировать тут особо нечего. Скажу лишь, что в отличие от Си, опустить фигурные скобки тут нельзя. Точнее говоря, способ есть, но о нем чуть ниже. Конструкции if-else и if-else-if-… на языке Perl выглядят следующим образом:

$a = shift ;
if ($a > 10 ) {
print "a > 10\n " ;
} else {
print "a <= 10\n " ;
}

if ($a > 0 ) {
# do something
} elsif ($a == 0 ) {
# do something
} else {
# do something else
}

В общем, все все как мы и ожидаем за одним исключением. Никакого «else if» в Perl нет — вместо этого следует использовать elsif и только его. Elsif может повторяться несколько раз, else использовать не обязательно, фигурные скобки опустить нельзя.

В отличие от других языков программирования, в Perl также предусмотрен оператор unless. Следующие два куска кода делают одно и то же:

unless ($a == 0 ) {
# "... если только a не равно нулю"
...
}

if ($a != 0 ) {
# то же самое
# ...
}

Unless можно использовать в сочетании с elsif и else, однако никакого «elsunless» в Perl нет.

В Perl есть возможность уменьшить объем кода, если в случае выполнения условия должна быть выполнена только одна строка кода. Следующие примеры делают одно и то же:


if ($a > $b ) {
exit 1 ;
}


unless ($b == $c ) {
exit 2 ;
}

# если условие истинное - завершить скрипт с кодом 1
exit 1 if ($a > $b ) ;
# если b == c, продолжить выполнение скрипта
exit 2 unless ($b == $c ) ;

При этом скобки в последнем примере можно не использовать:

# если условие истинное - завершить скрипт с кодом 1
exit 1 if $a > $b ;

Если вы пишите на Java/PHP или другом Си-подобном языке, такая конструкция скорее всего будет для вас непривычной, но на практике она действительно удобна. В русском языке мы ведь тоже обычно говорим «завершить программу, если …», а не «если …, то …».

Также, как в C/C++ и PHP, в Perl имеется тернарный оператор?: . Работает он аналогично конструкции if-else, только внутри выражений:

if ($a > $b ) {
$a = $a / $b ;
} else {
$a = $b / $a ;
}

# аналогичный код, использующий оператор "знак вопроса"
# одна строчка кода вместо пяти
$a = $a > $b ? $a / $b: $b / $a ;

Также хотелось бы сказать пару слов об операторах сравнения. Операторы сравнения в языке Perl делятся на две группы — производящие сравнение чисел и сравнение строк.

Как вы помните, скаляры в Perl можно интерпретировать либо как строки, либо как числа. Например, число 123 больше числа 45, однако строка «123» меньше строки «45». Вот для чего потребовалось несколько групп операторов сравнения. Сравнение строк в Perl производится таким же образом, как и в других современных языках программирования, потому я надеюсь, что тут вопросов не возникает.

Циклы for, foreach, while/until, do..while/until

Цикл for прекрасно знаком всем программистам:

# вывести строку "0 1 2 3 4"
for ($i = 0 ; $i < 5 ; $i ++ ) {
print "$i " ;
}

В круглых скобках через точку с запятой записывается:

  1. Код, выполняемый перед началом цикла.
  2. Условие, проверяемое перед началом (а не в конце, как думают многие) каждой итерации. Если оно ложно, выполнение цикла завершается.
  3. Код, выполняемый после каждой итерации.

Как и в случае с условными операторами, в циклах опускать фигурные скобки нельзя (для этого также есть специальная форма записи — см ниже).

Цикл foreach должен быть хорошо знаком программистам на PHP:

@arr = (0 , 1 , 2 , 3 , 4 ) ;
# вывести строку "0 1 2 3 4"
foreach $i (@arr ) {
print "$i " ;
}

Тело цикла foreach выполняется для каждого элемента массива, указанного в скобках. Важная особенность foreach — в переменную $i не копируется элемент массива @arr, как думают многие . Переменная $i в теле цикла — это и есть сам элемент массива . Таким образом, следующий код увеличивает на единицу значение каждого элемента массива @arr:

$i = 19880508 ;
foreach $i (@arr ) {
$i ++;
}
# $i по прежнему равен 19880508

Также foreach можно использовать для работы с хэшами:

%hash = (
aaa => 1 ,
bbb => 2 ,
) ;
# функция keys возвращает массив, содержащий все ключи хэша
foreach $k (keys %hash ) {
print "$k => $hash{$k}\n " ;
}

В Perl цикл foreach имеет короткую форму:

# если Вы забыли, что делает оператор qw,
# вернитесь к первой части "основ программирования на Perl"
for $i (qw/1 2 3/ ) {
print "$i " ;
}

То есть фактически везде вместо foreach можно писать просто for. Perl не перепутает такую запись с настоящим циклом for, потому что в последнем нужно писать точки с запятой и так далее.

Циклы while, until и do работают точно так же, как и в C++ или Pascal/Delphi:

# выводим "1 2 3 4 5" четырьмя разными способами

$i = 0 ;
while ($i < 5 ) { # пока $i меньше пяти
print ++ $i . " " ;
}
print "\n " ; # новая строка

$i = 0 ;
until ($i == 5 ) { # пока $i не станет равно пяти
print ++ $i . " " ;
}
print "\n " ;

$i = 0 ;
do {
print ++ $i . " " ;
} while ($i < 5 ) ; # проверка в конце цикла
print "\n " ;

$i = 0 ;
do {
print ++ $i . " " ;
} until ($i == 5 ) ;
print "\n " ;

По аналогии с операторами if и unless, существует сокращенная форма записи циклов:

$i = 0 ;
print ++ $i . " " while ($i < 5 ) ;
print "\n " ;

$i = 0 ;
print ++ $i . " " until ($i == 5 ) ;
print "\n " ;

print "$_ " for (qw/1 2 3 4 5/ ) ; # можно и foreach(qw/1 2 3 4 5/);
print "\n " ;

Обратите внимание на последний цикл foreach. Мы ведь помним, что это сокращенная запись foreach, а не цикл for, верно? Последний кстати не имеет короткой записи. Так вот, здесь не было указано имя переменной, с помощью которой мы будем обращаться к элементам массива. В сокращенной записи foreach ее нельзя использовать. В этом случае используется специальная переменная — $_. Следующий пример также вполне рабочий:

for (qw/1 2 3 4/ ) {
print "$_" ;
}

Его, кстати, можно переписать следующим образом.

6.5.1. Простые операторы

Простой оператор в PERLе — это выражение, которое может иметь единственный модификатор. Каждый простой оператор должен закачиваться точкой с запятой, если только он не является последним оператором в блоке; в этом случае точка с запятой может быть опущена. Существует пять модификаторов простых операторов:

$count = 5; print "$count\n" if $count; print "$count\n" while $count--; @people = qw/Анна Борис Виктор/; print "$_\n" foreach @people;

Мы можем применять модификаторы не только к простым операторам, но и к блокам. Для этого перед блоком нужно поставить ключевое слово do :

Do { $line = ; ... } until $line eq ".\n";

Такой блок всегда исполняется хотя бы раз до проверки условия. Обратите внимание, что в таких конструкциях не работают операторы управления циклом, поскольку модификаторы не имеют меток.

Конструкция do БЛОК (без модификатора) также используется в PERLе: она позволяет превратить блок в выражение и возвращает значение последнего оператора в этом блоке.

6.5.2. Составные операторы

Составные операторы состоят из блоков , заключенных в фигурные скобки. Напомним, что, в отличие от языков C или Java, фигурные скобки в составных операторах обязательны, даже если в них заключен только один оператор. PERL содержит следующие составные операторы:

6.5.2.1. Условный оператор if

Условный оператор if позволяет проверить определенное условие и, в зависимости от его истинности, выполнить ту или иную последовательность операторов. Он имеет следующие формы:

if (выражение ) БЛОК1 if (выражение ) БЛОК1 else БЛОК2 if (выражение1 ) БЛОК1 elsif (выражение2 ) БЛОК2 ... else БЛОКn

выражение истинно, то выполняется БЛОК1 ; если оно ложно, то управление передается оператору, следующему за if .

выражение истинно, то выполняется БЛОК1 ; если оно ложно, то выполняется БЛОК2 .

Третья форма оператора означает, что если выражение истинно, то выполняется БЛОК1 ; если оно ложно и истинно выражение2 , то выполняется БЛОК2 и т. д. Если ложны выражения во всех ветках оператора, то выполняется БЛОКn .

Следующий пример присваивает переменной $m наибольшее из трех чисел $x , $y , $z:

If ($x >= $y) { $m = ($x >= $z) ? $x: $z; } else { $m = ($y >= $z) ? $y: $z; }

6.5.2.2. Условный оператор unless

Условный оператор unless if . Он имеет две формы:

unless (выражение ) БЛОК1 unless (выражение ) БЛОК1 else БЛОК2

Первая форма оператора означает, что если выражение ложно, то выполняется БЛОК1 ; если оно истинно, то управление передается оператору, следующему за unless .

Вторая форма оператора означает, что если выражение ложно, то выполняется БЛОК1 ; если оно истинно, то выполняется БЛОК2 .

Предыдущий пример можно переписать так:

Unless ($x < $y) { $m = ($x >= $z) ? $x: $z; } else { $m = ($y >= $z) ? $y: $z; }

6.5.2.3. Оператор цикла while

Оператор цикла while имеет две формы:

while (выражение ) БЛОК while (выражение ) БЛОК continue БЛОК1

Оператор while

  1. Вычисляется значение выражения
  2. Выполняется БЛОК .
  3. continue , то выполняется БЛОК1 .

$i = 0; while ($i++ < 10) { print "$i\n" }

Пользуясь второй формой оператора while , его можно записать так:

$i = 1; while ($i <= 10) { print "$i\n" } continue { $i++ }

При использовании данного оператора необходимо убедиться, что рано или поздно выражение станет ложным, т. к. иначе программа войдет в бесконечный цикл, например:

While (1) { print "Привет всем!" }

6.5.2.4. Оператор цикла until

Оператор цикла until логически противоположен оператору while и также имеет две формы:

until (выражение ) БЛОК until (выражение ) БЛОК continue БЛОК1

Оператор until выполняется следующим образом:

  1. Вычисляется значение выражения . Если оно истинно, то управление передается оператору, следующему за данным оператором.
  2. Выполняется БЛОК .
  3. Если оператор содержит ключевое слово continue , то выполняется БЛОК1 .
  4. Управление передается этапу 1.

Следующий пример выводит на экран числа от одного до десяти:

$i = 1; until ($i > 10) { print "$i\n" } continue { $i++ }

6.5.2.5. Оператор цикла for

Оператор цикла for имеет вид:

for (инициализация ; условие ; изменение ) БЛОК

Оператор for выполняется следующим образом:

  1. Выполняется оператор инициализация (обычно он инициализирует счетчик или счетчики цикла).
  2. Вычисляется значение выражения условие . Если оно ложно, то управление передается оператору, следующему за данным оператором.
  3. Выполняется БЛОК .
  4. Выполняется оператор изменение (обычно он увеличивает или уменьшает счетчик или счетчики цикла) и управление передается этапу 2.

Данный оператор обычно используется в тех случаях, когда количество повторений цикла известно заранее. Так, мы могли бы записать предыдущий пример короче:

For ($i = 1; $i <= 10; $i++) { print "$i\n" }

6.5.2.6. Оператор итерации foreach

Оператор foreach выполняет заданные действия для каждого элемента списка или массива. Он имеет две формы:

foreach переменная (список ) БЛОК foreach переменная (список ) БЛОК continue БЛОК1

Оператор foreach выполняется следующим образом:

  1. Переменной присваивается очередной элемента списка . Если список исчерпан, то управление передается оператору, следующему за данным.
  2. Выполняется БЛОК .
  3. Если оператор содержит ключевое слово continue , то выполняется БЛОК1 .
  4. Управление передается этапу 1.

Приведем все тот же пример с печатью чисел от 1 до 10:

Foreach $i (1..10) { print "$i\n" }

Переменная является локальной для данного оператора, т. е. после завершения итерации ее предыдущее значение восстанавливается. Если перед переменной поставить ключевое слово my , то она будет лексически ограничена телом оператора. Если переменная опущена, то используется специальная переменная $_ :

Foreach (1..10) { print "$_\n" }

Если одним из элементов списка является массив, то тело цикла не должно его изменять, иначе результаты непредсказуемы.

В действительности, операторы for и foreach являются синонимами, и вы можете использовать любое из этих слов по своему усмотрению.

6.5.2.7. Метки операторов

Перед операторами while , until , for и foreach , а также перед блоками могут ставиться метки . Помеченный оператор имеет вид:

метка : оператор

В качестве метки может использоваться любой идентификатор, который не является зарезервированным словом, но на PERLе принято писать метки заглавными буквами.

Хотя в современном программировании использование меток считается дурным тоном, в некоторых случаях их применение существенно упрощает логику программы. Чаще всего это происходит, когда метки используются для передачи управления из глубоко вложенного цикла к внешнему. Рассмотрим следующий пример, написанный в лучший традициях C++:

For (my $i = 0; $i < @ary1; $i++) { for (my $j = 0; $j < @ary2; $j++) { if ($ary1[$i] > $ary2[$j]) { last; } $ary1[$i] += $ary2[$j]; } }

Метки и операторы управления циклом позволяют записать этот алгоритм намного короче и, главное, намного прозрачнее:

OUTER: for my $x (@ary1) { for my $y (@ary2) { next OUTER if $x > $y; $x += $y; } }

6.5.2.8. Оператор last

Оператор last немедленно завершает указанный цикл. Он имеет две формы:

last метка last

Первая форма оператора завершает выполнение цикла с заданной меткой . Вторая форма завершает выполнение самого внутреннего из выполняющихся в данный момент вложенных циклов. Если цикл имеет блок continue , то он не выполняется. Пример:

LINE: while () { last LINE if /^$/; # прервать цикл, если встретилась пустая строка... }

6.5.2.9. Оператор next

Оператор next начинает новую итерацию указанного цикла. Он имеет две формы:

next метка next

меткой continue , то он будет выполнен перед началом новой итерации. Пример:

LINE: while () { next LINE if /^#/; # пропускать комментарии... }

6.5.2.10. Оператор redo

Оператор redo начинает новую итерацию указанного цикла без проверки условия его выполнения. Он имеет две формы:

redo метка redo

Первая форма оператора начинает новую итерацию цикла с заданной меткой . Вторая форма начинает новую итерацию самого внутреннего из выполняющихся в данный момент вложенных циклов. Если цикл имеет блок continue , то он не выполняется. Следующий пример удаляет комментарии из программы на языке Pascal, где они имеют вид {…} (пример упрощен, т. к. не учитывает, что символы {} могут содержаться в строковых константах):

LINE: while () { while (s|({.*}.*){.*}|$1 |) {} s|{.*}| |; if (s|{.*| |) { $front = $_; while () { if (/}/) { s|^|$front\{|; redo LINE; } } } print; }

6.5.2.11. Блок как вырожденный цикл

Блок рассматривается в PERLе как цикл, безусловно выполняющийся один раз. Это означает, что мы можем использовать конструкцию

БЛОК1 continue БЛОК2

которая обычно означает, что выполняется БЛОК1 , а после него БЛОК2 . Однако, трактовка блоков как циклов означает и то, что мы можем пользоваться внутри блоков операторами управления циклом, и в этом случае указанная конструкция становится очень полезной.

Одна из причин, по которым в PERL не включен оператор выбора switch , состоит в том, что очень легко моделируется с помощью блоков и операторов управления циклом, например:

SWITCH: { $abc = 1, last SWITCH if /^abc/; $def = 1, last SWITCH if /^def/; $xyz = 1, last SWITCH if /^xyz/; $nothing = 1; }

6.5.2.12. Оператор перехода goto

PERL содержит оператор перехода goto трех видов:

goto метка goto выражение goto &имя

Первая форма оператора передает управление оператору с указанной меткой . Управление не может быть передано внутрь конструкции, требующей инициализации, например, внутрь подпрограммы или оператора foreach .

Вторая форма — это "вычисляемый goto ": он вычисляет значение выражения и передает управление на полученную в результате метку, например:

Goto ("LABEL1", "LABEL2", "LABEL3")[$i];

Третья форма — это вообще не goto в обычном смысле слова. Этот оператор подставляет вызов подпрограммы имя вместо выполняющейся сейчас подпрограммы. Она используется подпрограммами AUTOLOAD(), которые хотят незаметно подменить вызов одной подпрограммы другой. Имя не обязано быть именем подпрограммы; это может быть скалярная переменная или блок, значением которых является ссылка на подпрограмму.

Операторы в Perl-е имеют различный приоритет. Операторы, заимствованные из C , сохранили между собой ту же иерархию, что и в C . Термы имеют самый большой приоритет, они содержат переменные, кавычки, выражения в скобках, функции с их параметрами. Если за списковым оператором (например, print()) или унарным оператором (например, chdir()) следует список аргументов, заключенный в скобки, то эта последовательность имеет самый высокий приоритет, подобно функции с аргументами. Аналогично термам обрабатываются последовательности do{} и eval{} .

3.4.2 Оператор ``стрелка""

Также, как в С и С++ ``- > "" является инфиксным оператором ссылки. Если правая часть является [...] или {...} подпрограммой, тогда левая часть должна быть символьной ссылкой на массив или хэш. Если правая часть - это имя метода или скалярная переменная содержащая имя метода, то левая часть должна быть объектом или именем класса.

П2.3.4.3 Операторы ++ и - -

Эти операторы работают также как и в С. То есть, если они стоят перед переменной, то они увеличивают или уменьшают переменную до возвращения значения. Если они стоят после переменной, то увеличение или уменьшение переменной происходит после возврата значения. Если переменная содержит в себе число или употребляется в скалярном контексте, то использование ++ дает обычное увеличение значения. Если же переменная употреблялась только в строковом контексте, не является пустой строкой и содержит символы a-z,A-Z,0..9 , то происходит строковое увеличение значения переменной:
print ++($foo = "99"); - напечатает 100
print ++($foo = "a0"); - напечатает a1
print ++($foo = "Az"); - напечатает Ba
print ++($foo = "zz"); - напечатает aaa

3.4.4 Экспоненциальный оператор

В Perl-е двойная звездочка ** является экспоненциальным оператором. Он требует к себе даже больше внимания, чем унарный минус: -2**4 это -(2**4) , но не (-2)**4 .

3.4.5 Символьные унарные операторы

Унарный! означает логическое отрицание. Унарный минус, в случае числового значения переменной, обозначает обычное арифметическое отрицание. Если операндом является идентификатор, то возвращается строка, состоящая из знака минус и идентификатора. Если строка начинается со знака + или - , то возвращается строка, начинающаяся с противоположного знака. Унарная тильда `` ~ "" обозначает побитовое отрицание.
Унарный плюс не имеет влияния даже на строки. Он используется для отделения имя функции от выражения заключенного в скобки, которое иначе рассматривается как список аргументов.

Rand (10) * 20; - (rand10) * 20; rand +(10) * 20; - rand(10 * 20); Унарный бэкслэш ``"" обозначает ссылку на то, что стоит за ним.

3.4.6 Операторы связки

Знак равенства с тильдой ``= ~ ""связывает выражение слева с определенным шаблоном. Некоторые операторы обрабатывают и модифицируют переменную $_ . Эти же операции иногда желательно бывает выполнить над другой переменной. Правый аргумент это образец поиска, подстановки или трансляции, левый аргумент - это то, что должно быть подставлено вместо $_ . Возвращаемая величина показывает успех операции. Бинарное ``! ~ "" это тоже самое, что и ``= ~ "", только возвращаемая величина является отрицательной в логическом смысле.

3.4.7 Бинарные операторы

Звездочка * - умножение двух чисел. Cлэш / - деление числа на число. Процент % - вычисляет модуль двух чисел, x - оператор повторения. В скалярном контексте возвращает строку, состоящую из многократно повторенного левого операнда, причем повторяется он то количество раз, которое стоит справа. В списковом контексте он многократно повторяет список. print "a" x 80; напечатает букву a 80 раз.
@ones = (1) x 80; массив из восьмидесяти единиц.
@ones = (5) x @ones сделает все элементы равными пяти.
Бинарный плюс - операция сложения двух чисел.
Бинарный минус - операция вычитания двух чисел.
Бинарная точка - конкатенация строк.

3.4.8 Операторы сдвига

Двоичный сдвиг осуществляется, как и во многих других языках программирования, с помощью операторов ``<<"" и ``>>"". При применении этих операторов значения левых аргументов сдвигаются в соответствующую сторону на количество разрядов, указанное в правых аргументах. Аргументы должны быть целочисленными.

3.4.9 Операторы сравнения

``<"" - возвращает TRUE если левый аргумент численно меньше, чем правый.
``>"" - возвращает TRUE если правый аргумент численно меньше, чем левый.
``<="" - возвращает TRUE если правый аргумент численно меньше или равен левому.
``>="" - возвращает TRUE если левый аргумент численно меньше или равен правому.
``gt"" - возвращает TRUE если левый аргумент меньше (в строковом контексте), чем правый.
``lt"" - возвращает TRUE если правый аргумент меньше (в строковом контексте), чем левый.
На поведение операторов lt и gt влияют установки системного языка, если операционная система способна работать с несколькими языками. По этой причине операторы должны корректно работать со строками на языках, отличных от US ASCII , что в системе UNIX задается указанием свойств LC_COLLATE системного locale .

3.4.10 Операторы эквивалентности

Возвращает TRUE , если левый аргумент численно эквивалентен правому.
!= возвращает TRUE , если левый аргумент численно неэквивалентен правому.
<=> возвращает -1, 0 или 1 в зависимости от того, численно меньше, равен или больше левый аргумент правого.
eq возвращает TRUE , если левый аргумент эквивалентен правому (в строковом контексте).
ne возвращает TRUE , если левый аргумент неэквивалентен правому (в строковом контексте).
cmp возвращает -1, 0 или 1 в зависимости от того, меньше равен или больше левый аргумент правого (в строковом контексте).

3.4.11 Побитовое И, побитовое ИЛИ и Исключающее ИЛИ

Бинарное & возвращает объединенные побитово операнды.
Бинарное | возвращает перемноженные побитово операнды.
Бинарное ^ возвращает исключенные побитово операнды.

3.4.12 Логическое И и логическое ИЛИ

Бинарное && - логическое И. Если левый аргумент FALSE , то правый не проверяется.
Бинарное || - логическое ИЛИ. Если левый аргумент TRUE , то правый аргумент не проверяется.
||""и && отличаются от подобных операторов в \verb C| тем, что вместо 0 или 1 они возвращают последнюю обработанную величину. Таким образом, наиболее удобным способом определить домашний каталог пользователя из переменной окружения HOME будет (на практике такой способ определения домашнего каталога пользователя не рекомендуется):

$home = $ENV{"HOME"} || $ENV{"LOGDIR"} || (getpwuid($<)) || die "You"re homeless!\n"; В качестве более удобной для чтения альтернативы Perl поддерживает операторы and и or , которые будут описаны далее. Их приоритет ниже, однако их можно с удобством использовать, не расставляя скобки, после операторов, аргументами которых являются списки: unlink "alpha", "beta", "gamma" or gripe(), next LINE; Если писать в стиле C , то это может быть записано так: unlink("alpha", "beta", "gamma") || (gripe(), next LINE);

3.4.13 Оператор диапазона

Оператор диапазона. Реально это два разных оператора, в зависимости от контекста. В списковом контексте он работает как оператор диапазона от левого аргумента до правого.

For (1..10) { #code } В скалярном контексте он возвращает булевское значение. Если левый операнд TRUE , то.. принимает значение TRUE , если правый операнд тоже TRUE . if (101..200) { print "hi;)";} - напечатает вторую сотню строк

3.4.14 Условный оператор

?: также как и в C является условным оператором. Он работает подобно if-then-else . Если аргумент перед? - TRUE , то возвращается аргумент перед: , в противоположном случае возвращается аргумент после: . Скалярный или списковый контекст второго и третьего аргументов передается по наследству.

($a_or_b ? $a: $b) = $c;

3.4.15 Операторы присваивания

Обычный оператор присваивания. Вообще операторы присваивания работают также как и в C . $a += 2; - то же самое, что и $a = $a + 2; Можно использовать следующие сокращения:

**= += *= &= <<= &&= -= /= |= >>= ||= .= %= ^= x= ($a += 2) *= 3; - то же самое, что и: $a = $a + 2; $a = $a * 3;

3.4.16 Оператор ``запятая""

Оператор запятая или comma-оператор. В скалярном контексте он обрабатывает левый аргумент и отбрасывает его значение, потом обрабатывает правый аргумент и возвращает его величину. В этом он подобен comma-оператору из C . В списковом контексте он играет роль разделителя аргументов и вставляет оба аргумента в список. => является синонимом comma-оператора.

3.4.17 Логическое НЕ

Унарное NOT возвращает отрицание аргумента. Оно эквивалентно! , за исключением более низкого приоритета.

П2.3.4.18 Логическое И, ИЛИ и Исключающее ИЛИ

and возвращает конъюнкцию двух выражений. Он эквивалентен && , за исключением более низкого приоритета. or возвращает дизъюнкцию аргументов. Он эквивалентен ||, за исключением более низкого приоритета. xor (eXclusive OR) - исключающее ИЛИ, возвращает истину, если истинен ровно один из аргументов.

3.4.19 Оператор чтения из файла

В Perl есть несколько операций ввода-вывода. Для вывода из файла используется команда <>.

Open(STDIN,"/etc/passwd"); while ($string = ) { @a = split(/[:]/,$string); } Внутри этих скобок стоит дескриптор файла. Считывание происходит построчно. В конце файла принимает значение FALSE и цикл while завершается. По умолчанию считывание происходит в переменную $_ . Нулевой дескриптор файла используется также как в sed и awk , то есть считывается поток из файлов перечисленных в командной строке.

3.4.20 Оператор замены строки

Оператор s/PATTERN/REPLACEMENT/egimosx производит поиск строки, соответствующей шаблону PATTERN и если строка найдена, то подстановку на ее место текста REPLACEMENT . Возвращает количество произведенных подстановок. Если перед этим не использовался оператор =~ или!~ для определения переменной, которая будет обрабатываться, то будет модифицироваться переменная $_ . Этот оператор используется со следующими опциями: e интерпретирует правую часть как выражение. g производит подстановку на место каждой строки, соответствующей шаблону. i производит поиск различающий большие и маленькие буквы. m обрабатывает строку, как состоящую из нескольких строк. o происходит подстановка только на место первой встреченной строки. s обрабатывает строку, как состоящую только из одной строки. x использует расширенные регулярные выражения. Например:

$path =~ s|/usr/local/bin|/usr/bin|; ($foo = $bar) =~ s/this/that/o; $count = ($paragraf =~ s/Mister\b/Mr./gm);

3.4.21 Оператор замены множества символов

tr/SEARCHLIST/REPLACEMENTLIST/cds y/SEARCHLIST/REPLACEMENTLIST/cds Заменяет все найденные символы из множества символов SEARCHLIST на соответствующие символы из множества символов REPLACEMENTLIST . Возвращает число символов, которые были заменены или удалены. Если посредством операторов =~, !~ не была указана никакая строка, то обрабатывается переменная $_ . y является синонимом tr . Если SEARCHLIST заключен в скобки, то REPLACEMENTLIST тоже заключается в скобки, которые могут отличаться от тех, в которые заключается шаблон, например:

Tr tr(+-*/)/ABCD/ Этот оператор употребляется со следующими опциями: c заменяет символы, которые не входят во множество SEARCHLIST на REPLACEMENTLIST , например: tr/a-zA-Z/ /cs; заменит неалфавитные символы. d Стирает символы, которые ни на что не заменяются. s Переводит последовательность символов, которые заменяются на один и тот же символ в один символ. Например: $a = "CCCCCCCCC"; $a =~ tr/C/D/s; теперь $a = "D"

И узнали, как числа и строки конвертируются друг в друга на лету. Мы даже мельком взглянули на условное выражение if , но пока что не узнали, как сравнить два скаляра. Об этом пойдет речь в этой части.

Если у нас есть две переменные $x и $y, можно ли их сравнить? Равны ли 1, 1.0 и 1.00? А как насчет "1.00"? Что больше - "foo" или "bar"?

Два набора операторов сравнения

В Perl существует два набора операторов сравнения. Так же, как с уже изученными нами бинарными операторами сложения (+), конкатенации (.) и повторения (x), здесь тоже оператор определяет, как ведут себя операнды и как они сравниваются.

Вот эти два набора операторов:

Числовое Строковое Значение == eq равно!= ne не равно < lt меньше > gt больше <= le меньше или равно >= ge больше или равно

Операторы слева сравнивают числовые значения, а справа (в средней колонке) сравнивают значения, основываясь на ASCII таблице или на текущей локали.

Рассмотрим несколько примеров:

Use strict; use warnings; use 5.010; if (12.0 == 12) { say "TRUE"; } else { say "FALSE"; } В этом простейшем случае Perl выведет TRUE, так как оператор == сравнивает два числа, так что Perl"у не важно, записаны ли они как целые числа, или как числа с плавающей точкой.

В следующем сравнении ситуация немного интереснее

"12.0" == 12

это выражение также истинно, ведь оператор Perl"а == конвертирует строку в число.

2 < 3 истинно, так как < сравнивает два числа. 2 lt 3 также истинно, ведь 2 находистя перед 3 в таблице ASCII. 12 > 3 очевидно, истинно. 12 gt 3 вернет FALSE

Возможно, с первого взгляда кому-то это покажется неожиданным, но если подумать, Perl ведь сравнивает строки посимвольно. Так что он сравнивает "1" и "3", и раз они отличаются и "1" стоит перед "3" в таблице ASCII, на этом этапе Perl решает, строковое значение 12 меньше, чем строковое значение 3.

Всегда нужно быть уверенным, что сравниваешь значение именно так, как нужно!

"foo" == "bar" будет истинно

Также это выдаст предупреждение, если(!) предупреждения включены с помощью use warnings . Причина его в том, что мы используем две строки как числа в числовом сравнении ==. Как упоминалось в предыдущей части, Perl смотрит на строку, начиная с левого конца, и конвертирует ее в число, которое там находит. Поскольку обе строки начинаются с букв, они будут конвертированы в 0. 0 == 0, так что выражение истинно.

С другой стороны:

"foo" eq "bar" ложно

Так что всегда нужно быть уверенным, что сравниваешь значение именно так, как нужно!

То же будет при сравнении

"foo" == "" будет истинно

"foo" eq "" будет ложно

Результаты в этой таблице могут пригодиться:

12.0 == 12 ИСТИНА "12.0" == 12 ИСТИНА "12.0" eq 12 ЛОЖЬ 2 < 3 ИСТИНА 2 lt 3 ИСТИНА 12 > 3 ИСТИНА 12 gt 3 ЛОЖЬ! (внимание, может быть неочевидно с первого взгляда) "foo" == "" ИСТИНА! (Выдает предупреждение, если использована прагма "warnings") "foo" eq "" ЛОЖЬ "foo" == "bar" ИСТИНА! (Выдает предупреждение, если использована прагма "warnings") "foo" eq "bar" ЛОЖЬ

И наконец пример, когда можно попасть в ловушку, получив некоторые данные от пользователя, и, аккуратно отрезав перевод строки в конце, проверить, не является ли строка пустой.

Use strict; use warnings; use 5.010; print "input: "; my $name = ; chomp $name; if ($name == "") { # неверно! здесь нужно использовать eq вместо == ! say "TRUE"; } else { say "FALSE"; }

Если запустить этот скрипт и ввести "abc", мы получим ответ TRUE, так как perl решил, что "abc" это то же, что и пустая строка.

Для сравнения скалярных данных или значений скалярных переменных язык Perl предлагает набор бинарных операций, вычисляющих отношения равенства, больше, больше или равно и т. п. между своими операндами, поэтому эту группу операций еще называют операциями отношения. Для сравнения числовых данных и строковых данных Perl использует разные операции. Все они представлены в табл. 4.1.

Таблица 4.1. Операции отношения

Операция Числовая Строковая Значение
Равенство == eq Истина, если операнды равны, иначе ложь
Неравенство != ne Истина, если операнды не равны, иначе ложь
Меньше < lt Истина, если левый операнд меньше правого, иначе ложь
Больше > gt Истина, если левый операнд больше правого, иначе ложь
Меньше или равно <= le Истина, если левый операнд больше правого или равен ему, иначе ложь
Больше или равно >= ge Истина, если правый операнд больше левого или равен ему, иначе ложь
Сравнение <=> cmt 0, если операнды равны
1, если левый операнд больше правого
-1, если правый операнд больше левого

Результатом операций отношения (кроме последней сравнения) является Истина, значение 1, или Ложь, пустая строка "".

Замечание
Значение истина в арифметических операциях интерпретируется как число 1, а в строковых как строка "1". Значение ложь в арифметических операциях интерпретируется как число 0, а в строковых как пустая строка " ".

Числовые операции отношения

Числовые операции отношения применяются к числовым данным, причем один или оба операнда могут задаваться строкой, содержащей правильное десятичное число. Если в числовых операциях отношения какой-либо из операндов задан строкой, содержимое которой не представляет правильное десятичное число, то его значение принимается равным о и отображается предупреждение о некорректном использовании операнда в числовой операции отношения (если включен режим отображения предупреждений интерпретатора Perl). Смысл операций отношения для числовых данных соответствует обычным математическим операциям сравнения чисел (пример 4.7).

123 > 89; # Результат: 1 (истина)

123 < 89; # Результат: "" (ложь)

123 <= 89; # Результат: "" (ложь)

89 <= 89; # Результат: 1 (истина)

23 >= 89; # Результат: "" (ложь)

23 <=> 89; # Результат: -1 (правый операнд больше левого)

89 <=> 23; # Результат: 1 (правый операнд больше левого)

Применение числовых операций сравнения не представляет сложности, однако при сравнении на равенство десятичных чисел с плавающей точкой могут проявиться эффекты округления, связанные с ограниченным количеством значащих цифр в мантиссе представления действительных чисел в компьютере и приводящие к "неправильной", с точки зрения пользователя работе операций сравнения. Пример 4.8 иллюстрирует подобную ситуацию.

#! peri -w
$z = 0.7;

$zz = 10+0.7-10; # Переменная $zz содержит число 0.7

# Печать строки "z равно zz", если равны значения переменных $z и $zz print "z равно zz\n" if ($z == $zz);

При попытке выполнить пример 4.8 мы с удивлением обнаружим, что наша программа ничего не напечатает. В чем же дело? Разгадка лежит в операторе вычисления значения переменной $zz. При выполнении арифметических операций в результате ошибок округления получается значение 0.699999999999999 (можете вставить оператор печати переменной $zz и убедиться в этом), хотя и близкое к 0.7, но не равное ему в точности. Следовательно, операция сравнения отработала верно!

Совет
Не используйте операцию сравнения на равенство вещественных чисел, ее результат может не соответствовать ожидаемому с точки зрения математики. Если необходимо проверить равенство двух вещественных чисел, то лучше сравнивать абсолютное значение их разности с некоторым очень маленьким числом (в зависимости от требуемой точности):

abs($a-$b) <= 0.00000001; # Проверка равенства

Строковые операции отношения

Сравнение строковых данных базируется на их упорядочении в соответствии с таблицей кодов ASCII, т. е. символ с меньшим кодом ASCII предшествует символу с большим кодом. Сравнение строк осуществляется посимвольно слева направо. Это означает, что если равны первые символы строк, то сравниваются вторые и если они равны, то сравниваются третьи и т. д. Причем, если строки разной длины, то в конец строки меньшей длины добавляется недостающее для равенства количество символов с кодом о. Следует отметить, что в отличие от некоторых других языков программирования в Perl замыкающие строку пробельные символы являются значимыми при сравнении строк. В примере 4.9 показаны сравнения строк, иллюстрирующие изложенные правила.

"A" It "a"; # Результат: истина (код "А" - \101, код "а" - \141)
"a" It "aa";
# с кодом \000, который меньше кода \141
# второго символа "а" строки правого операнда)
"a" It "a "; # Результат: истина (к строке "а" добавляется символ
# с кодом \000, который меньше кода \040
# замыкающего пробела строки правого операнда)
"12" It "9"; # Результат: истина (код "1" - \061, код "9" - \071)
"9" eq 09"; # Результат: ложь (код " " - \040, код "О" - \060)

Обратим внимание на две последние операции сравнения строковых литералов. Содержимое их операндов может быть преобразовано в правильные числа, и поэтому к ним применимы аналогичные числовые операции отношения. Однако их результат будет существенно отличаться от результата выполнения строковых операций отношения. При использовании операции < в предпоследнем выражении результат будет Ложь, а если в последнем выражении применить операцию ==, то результат будет Истина. Об этом всегда следует помнить, так как Perl автоматически преобразует символьные данные в числовые там, где это необходимо.