Spec-Zone.ru › Perl 5.32

perlop

СОДЕРЖАНИЕ

  • НАЗВАНИЕ
  • ОПИСАНИЕ
    • Приоритет и ассоциативность операторов
    • Операторы терминов и списков (слева направо)
    • Оператор стрелки
    • Автоинкремент и автодекремент
    • Возведение в степень
    • Символические унарные операторы
    • Операторы связывания
    • Мультипликативные операторы
    • Аддитивные операторы
    • Операторы сдвига
    • Именованные унарные операторы
    • Операторы сравнения
    • Операторы равенства
    • Оператор экземпляра класса
    • Оператор smartmatch
      • Smartmatch объектов
    • Битовое И
    • Битовое ИЛИ и исключающее ИЛИ
    • Логическое И (стиль C)
    • Логическое ИЛИ (стиль C)
    • Определенное логическое ИЛИ
    • Операторы диапазона
    • Условный оператор
    • Операторы присваивания
    • Оператор запятой
    • Операторы списков (справа налево)
    • Логическое НЕ
    • Логическое И
    • Логическое ИЛИ и исключающее ИЛИ
    • Операторы C, отсутствующие в Perl
    • Операторы кавычек и похожие на них
    • Операторы regexp-кавычек
    • Операторы похожие на кавычки
    • Подробности разбора строковых конструкций
    • Операторы ввода/вывода
    • Сворачивание констант
    • Пустые операции
    • Битовые строковые операторы
    • Целочисленная арифметика
    • Арифметика с плавающей запятой
    • Более большие числа

НАЗВАНИЕ

perlop - Операторы Perl и приоритеты

ОПИСАНИЕ

В Perl оператор определяет выполняемую операцию, независимо от типа операндов. Например, $x + $y всегда является численным сложением, а если $x или $y не содержат чисел, то сначала выполняется попытка их преобразования в числа.

Это отличается от многих других динамических языков, где операция определяется типом первого аргумента. Это также означает, что Perl имеет два варианта некоторых операторов, один для числового и один для строкового сравнения. Например, $x == $y сравнивает два числа на равенство, а $x eq $y сравнивает две строки.

Однако есть несколько исключений: x может быть либо повторением строки, либо повторением списка, в зависимости от типа левого операнда, а также &, |, ^ и ~ могут быть либо строковыми, либо числовыми битовыми операциями.

Приоритет и ассоциативность операторов

Приоритет и ассоциативность операторов в Perl работают примерно так же, как и в математике.

Приоритет операторов означает, что некоторые операторы группируются сильнее, чем другие. Например, в 2 + 4 * 5, умножение имеет более высокий приоритет, поэтому 4 * 5 группируется вместе как правый операнд сложения, а не 2 + 4 группируется вместе как левый операнд умножения. Это как если бы выражение было написано 2 + (4 * 5), а не (2 + 4) * 5. Поэтому выражение даёт 2 + 20 == 22, а не 6 * 5 == 30.

Ассоциативность операторов определяет, что происходит, если используется последовательность одинаковых операторов один за другим: обычно они будут группироваться слева или справа. Например, в 9 - 3 - 2, вычитание является левоассоциативным, поэтому 9 - 3 группируется вместе как левый операнд второго вычитания, а не 3 - 2 группируется вместе как правый операнд первого вычитания. Это как если бы выражение было написано (9 - 3) - 2, а не 9 - (3 - 2). Поэтому выражение даёт 6 - 2 == 4, а не 9 - 1 == 8.

Для простых операторов, которые вычисляют все свои операнды, а затем объединяют значения каким-либо образом, приоритет и ассоциативность (и скобки) подразумевают некоторые требования к порядку этих объединяющих операций. Например, в 2 + 4 * 5, группировка, подразумеваемая приоритетом, означает, что умножение 4 и 5 должно быть выполнено до сложения 2 и 20, просто потому, что результат этого умножения требуется в качестве одного из операндов сложения. Но порядок операций не полностью определяется этим: в 2 * 2 + 4 * 5 оба умножения должны быть выполнены до сложения, но группировка ничего не говорит о порядке выполнения двух умножений. На самом деле в Perl существует общее правило, что операнды оператора вычисляются в порядке слева направо. Несколько операторов, таких как &&= , имеют специальные правила вычисления, которые могут привести к тому, что операнд вообще не будет вычисляться; в общем случае оператор верхнего уровня в выражении управляет вычислением операндов.

Некоторые операторы сравнения, как и их ассоциативность, цепляются с некоторыми операторами того же приоритета (но никогда с операторами разного приоритета). Эта цепочка означает, что каждое сравнение выполняется над двумя аргументами, окружающими его, и каждый внутренний аргумент участвует в двух сравнениях, а результаты сравнения неявно ANDятся. Таким образом, "$x < $y <= $z" ведёт себя точно так же, как "$x < $y && $y <= $z", предполагая, что "$y" - это простая скалярная величина, как кажется. И ANDing короткое замыкание, подобно тому, как делает "&&" , останавливая последовательность сравнений, как только одно из них даёт ложное значение.

В цепочечном сравнении каждый выражение аргумента вычисляется не более одного раза, даже если он участвует в двух сравнениях, но результат вычисления извлекается для каждого сравнения. (Он вообще не вычисляется, если короткое замыкание означает, что он не нужен ни для одного сравнения.) Это важно, если вычисление внутреннего аргумента дорогостоящее или недетерминированное. Например,

if($x < expensive_sub() <= $z) { ...

не совсем похоже на

if($x < expensive_sub() && expensive_sub() <= $z) { ...

а вместо этого ближе к

my $tmp = expensive_sub();
if($x < $tmp && $tmp <= $z) { ...

в том, что подпрограмма вызывается только один раз. Однако это не совсем так, как этот последний код, потому что цепочечное сравнение фактически не включает в себя никаких временных переменных (именованных или иных): присваивания нет. Это не имеет большого значения, когда выражение является вызовом обычной подпрограммы, но имеет большее значение с подпрограммой lvalue или если выражение аргумента даёт какой-то необычный вид скаляра другими средствами. Например, если выражение аргумента даёт связанную скалярную величину, то выражение вычисляется для получения этой скалярной величины не более одного раза, но значение этой скалярной величины может быть получено до двух раз, один раз для каждого сравнения, в котором оно фактически используется.

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

if ($x < $tied_scalar < $z) { ...

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

if ($x < $tied_scalar + 42 < $z) { ...

Некоторые операторы являются вместо этого неассоциативными, что означает, что использование последовательности этих операторов одного приоритета является синтаксической ошибкой. Например, "$x .. $y .. $z" - это ошибка.

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

left        terms and list operators (leftward)
left        ->
nonassoc    ++ --
right       **
right       ! ~ \ and unary + and -
left        =~ !~
left        * / % x
left        + - .
left        << >>
nonassoc    named unary operators
chained     < > <= >= lt gt le ge
chain/na    == != eq ne <=> cmp ~~
nonassoc    isa
left        &
left        | ^
left        &&
left        || //
nonassoc    ..  ...
right       ?:
right       = += -= *= etc. goto last next redo dump
left        , =>
nonassoc    list operators (rightward)
right       not
left        and
left        or xor

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

Многие операторы могут быть перегружены для объектов. См. overload.

Операторы терминов и списков (слева направо)

Термин имеет наивысший приоритет в Perl. К ним относятся переменные, операторы кавычек и похожие на них, любое выражение в скобках и любая функция, аргументы которой заключены в скобки. На самом деле, в этом смысле нет функций, только операторы списков и унарные операторы, которые ведут себя как функции, потому что вы ставите скобки вокруг аргументов. Всё это документировано в perlfunc.

Если за оператором списка (print(), и т. д.) или за унарным оператором (chdir(), и т. д.) следует левая круглая скобка в качестве следующего токена, оператор и аргументы в скобках считаются имеющими наивысший приоритет, как и при обычном вызове функции.

В отсутствие скобок приоритет операторов списка, таких как print, sort, или chmod, либо очень высок, либо очень низок, в зависимости от того, смотрите ли вы на левую или правую сторону оператора. Например, в

@ary = (1, 3, sort 4, 2);
print @ary;         # prints 1324

запятые справа от sort вычисляются до sort, но запятые слева вычисляются после. Другими словами, операторы списка, как правило, поглощают все последующие аргументы и затем ведут себя как простой ОПЕРАНД в отношении предшествующего выражения. Будьте внимательны со скобками:

# These evaluate exit before doing the print:
print($foo, exit);  # Obviously not what you want.
print $foo, exit;   # Nor is this.

# These do the print before evaluating exit:
(print $foo), exit; # This is what you want.
print($foo), exit;  # Or this.
print ($foo), exit; # Or even this.

Также обратите внимание, что

print ($foo & 255) + 1, "\n";

вероятно, не делает того, чего вы ожидаете на первый взгляд. Скобки заключают список аргументов для print, который вычисляется (выводя результат $foo & 255). Затем к возвращаемому значению print (обычно 1) добавляется единица. Результат будет примерно таким:

1 + 1, "\n";    # Obviously not what you meant.

Чтобы сделать то, что вы имели в виду, необходимо написать:

print(($foo & 255) + 1, "\n");

См. "Именованные унарные операторы" для более подробного обсуждения этого.

Также в качестве операндов анализируются конструкции do {} и eval {}, а также вызовы подпрограмм и методов, а также анонимные конструкторы [] и {}.

См. также "Операторы кавычек и подобные кавычкам" в конце этого раздела, а также "Операторы ввода/вывода".

Оператор стрелки

"->" является инфиксным оператором разыменования, как и в C и C++. Если правая часть — это [...], {...}, или индекс (...), то левая часть должна быть либо жесткой, либо символической ссылкой на массив, хеш или подпрограмму соответственно. (Или, говоря технически, местоположением, способным содержать жесткую ссылку, если используется ссылка на массив или хеш для присваивания.) См. perlreftut и perlref.

В противном случае правая часть — это имя метода или простая скалярная переменная, содержащая либо имя метода, либо ссылку на подпрограмму, а левая часть — либо объект (освященная ссылка), либо имя класса (то есть имя пакета). См. perlobj.

Случаи разыменования (в отличие от случаев вызова методов) несколько расширены благодаря функции postderef. Для получения подробной информации об этой функции обратитесь к разделу "Синтаксис постфиксного разыменования" в perlref.

Автоинкремент и автодекремент

"++" и "--" работают как в C. То есть, если они стоят перед переменной, то они увеличивают или уменьшают переменную на единицу перед возвратом значения, а если после, то увеличивают или уменьшают после возврата значения.

$i = 0;  $j = 0;
print $i++;  # prints 0
print ++$j;  # prints 1

Обратите внимание, что, как и в C, Perl не определяет, **когда** переменная увеличивается или уменьшается. Вам просто известно, что это произойдет до или после возврата значения. Это также означает, что изменение переменной дважды в одном операторе приведет к неопределенному поведению. Избегайте операторов вида:

$i = $i ++;
print ++ $i + $i ++;

Perl не гарантирует результат выполнения приведенных выше операторов.

Оператор автоинкремента имеет небольшую встроенную магию. Если вы увеличиваете числовую переменную или переменную, которая когда-либо использовалась в числовом контексте, вы получаете обычное увеличение. Однако, если переменная использовалась только в строковых контекстах с момента ее установки и имеет значение, отличное от пустой строки, и соответствует шаблону /^[a-zA-Z]*[0-9]*\z/, инкремент выполняется как строка, сохраняя каждый символ в своем диапазоне с переносом:

print ++($foo = "99");      # prints "100"
print ++($foo = "a0");      # prints "a1"
print ++($foo = "Az");      # prints "Ba"
print ++($foo = "zz");      # prints "aaa"

undef всегда обрабатывается как числовое, и, в частности, меняется на 0 перед инкрементом (чтобы пост-инкремент неопределенного значения возвращал 0, а не undef).

Оператор автодекремента не является магическим.

Возведение в степень

Бинарный оператор "**" — это оператор возведения в степень. Он связывает даже сильнее, чем унарный минус, поэтому -2**4 — это -(2**4), а не (-2)**4. (Это реализовано с помощью функции C pow(3) , которая фактически работает с числами с плавающей точкой внутри).

Обратите внимание, что некоторые выражения возведения в степень определены некорректно: это включает 0**0, 1**Inf и Inf**0. Не ожидайте каких-либо определенных результатов в этих особых случаях; результаты зависят от платформы.

Символические унарные операторы

Унарный "!" выполняет логическое отрицание, то есть "не". См. также not для версии с более низким приоритетом.

Унарный "-" выполняет арифметическое отрицание, если операнд является числовым, включая любые строки, похожие на числа. Если операндом является идентификатор, возвращается строка, состоящая из знака минус, соединённого с идентификатором. В противном случае, если строка начинается с плюса или минуса, возвращается строка, начинающаяся с противоположного знака. Одним из последствий этих правил является то, что -bareword эквивалентно строке "-bareword". Однако, если строка начинается с символа, не являющегося буквой (исключая "+" или "-" ), Perl попытается преобразовать строку в число, и выполнится арифметическое отрицание. Если строку нельзя чисто преобразовать в число, Perl выдаст предупреждение Argument "the string" isn't numeric in negation (-) at ....

Унарный "~" выполняет побитовое отрицание, то есть дополнение до 1. Например, 0666 & ~027 равно 0640. (См. также "Целочисленная арифметика" и "Побитовые строковые операторы".) Обратите внимание, что ширина результата зависит от платформы: ~0 имеет ширину 32 бита на 32-битной платформе, но 64 бита на 64-битной платформе, поэтому если вы ожидаете определённой ширины бита, помните, что нужно использовать оператор "&" для маскировки избыточных битов.

Начиная с Perl 5.28, попытка дополнения строки, содержащей символ с порядковым значением выше 255, является фатальной ошибкой.

Если функция "bitwise" включена с помощью use feature 'bitwise' или use v5.28, то унарный "~" всегда обрабатывает свой аргумент как число, а альтернативная форма оператора "~." всегда обрабатывает свой аргумент как строку. Таким образом, ~0 и ~"0" оба дадут 2**32-1 на 32-битных платформах, в то время как ~.0 и ~."0" оба вернут "\xff". До Perl 5.28 эта функция выводила предупреждение в категории "experimental::bitwise".

Унарный "+" не оказывает никакого влияния даже на строки. Он полезен синтаксически для отделения имени функции от выражения в скобках, которое в противном случае интерпретировалось бы как полный список аргументов функции. (См. примеры выше в разделе "Операнды и операторы списков (влево)".)

Унарный "\" создаёт ссылки. Если его операнд — это единственное обозначенное слово, он создаёт ссылку на этот объект. Если его операнд — это список в скобках, то он создаёт ссылки на упомянутые в нём вещи. В противном случае он помещает свой операнд в контекст списка и создаёт список ссылок на скаляры в списке, предоставленном операндом. См. perlreftut и perlref. Не путайте это поведение с поведением обратной косой черты внутри строки, хотя оба способа передают идею защиты следующего элемента от интерполяции.

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

Бинарный "=~" привязывает скалярное выражение к шаблону соответствия. Некоторые операции по умолчанию ищут или изменяют строку $_. Этот оператор заставляет такую операцию работать с другой строкой. Правый аргумент — это шаблон поиска, подстановки или транслитерации. Левый аргумент — это то, что должно быть найдено, заменено или транслитерировано вместо значения по умолчанию $_. При использовании в скалярном контексте возвращаемое значение, как правило, указывает на успех операции. Исключение составляют подстановка (s///) и транслитерация (y///) с опцией /r (недеструктивная), которые приводят к тому, что возвращаемое значение является результатом подстановки. Поведение в контексте списка зависит от конкретного оператора. См. "Операторы поиска по регулярным выражениям, подобные кавычкам" для получения подробностей и perlretut для примеров использования этих операторов.

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

'\\' =~ q'\\';

не является корректным, так как движок регулярных выражений в итоге попытается скомпилировать шаблон \, который он будет рассматривать как синтаксическую ошибку.

Бинарный "!~" похож на "=~", за исключением того, что возвращаемое значение логически инвертируется.

Бинарный "!~" с неразрушительной заменой (s///r) или транслитерацией (y///r) — синтаксическая ошибка.

Операторы умножения

Бинарный "*" умножает два числа.

Бинарный "/" делит два числа.

Бинарный оператор "%" — это оператор модуля, который вычисляет остаток от деления первого аргумента на второй. При заданных целочисленных операндах $m и $n: Если $n положительно, то $m % $n равно $m минус наибольшее кратное $n, меньшее или равное $m. Если $n отрицательно, то $m % $n равно $m минус наименьшее кратное $n, которое не меньше $m (то есть результат будет меньше или равен нулю). Если операнды $m и $n являются числами с плавающей точкой, и абсолютное значение $n (то есть abs($n)) меньше (UV_MAX + 1), в операции будут использоваться только целые части $m и $n (Примечание: здесь UV_MAX означает максимальное значение для беззнакового целочисленного типа). Если абсолютное значение правого операнда (abs($n)) больше или равно (UV_MAX + 1), "%" вычисляет остаток от деления с плавающей точкой $r в уравнении ($r = $m - $i*$n), где $i — определённое целое число, которое делает $r иметь тот же знак, что и правый операнд $n (не как левый операнд $m, как в функции C fmod()) и абсолютное значение меньше, чем у $n. Обратите внимание, что когда use integer находится в области действия, "%" даёт прямой доступ к оператору модуля, как он реализован вашим компилятором C. Этот оператор не так хорошо определён для отрицательных операндов, но он будет выполняться быстрее.

Бинарный оператор x — это оператор повторения. В скалярном контексте или если левый операнд не заключён в скобки и не является списком qw//, он выполняет повторение строки. В этом случае он предоставляет скалярный контекст левому операнду и возвращает строку, состоящую из левого операнда, повторившегося указанное правым операндом количество раз. Если x находится в контексте списка, а левый операнд заключён в скобки или является списком qw//, он выполняет повторение списка. В этом случае он предоставляет контекст списка левому операнду и возвращает список, состоящий из левого операнда, повторившегося указанное правым операндом количество раз. Если правый операнд равен нулю или отрицателен (с предупреждением об отрицательном значении), он возвращает пустую строку или пустой список в зависимости от контекста.

print '-' x 80;             # print row of dashes

print "\t" x ($tab/8), ' ' x ($tab%8);      # tab over

@ones = (1) x 80;           # a list of 80 1's
@ones = (5) x @ones;        # set all elements to 5

Операторы сложения

Бинарный оператор "+" возвращает сумму двух чисел.

Бинарный оператор "-" возвращает разность двух чисел.

Бинарный оператор "." конкатенирует две строки.

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

Бинарный оператор "<<" возвращает значение своего левого аргумента, сдвинутого влево на количество битов, указанных правым аргументом. Аргументы должны быть целыми числами. (См. также "Целочисленная арифметика".)

Бинарный оператор ">>" возвращает значение своего левого аргумента, сдвинутого вправо на количество битов, указанных правым аргументом. Аргументы должны быть целыми числами. (См. также "Целочисленная арифметика".)

Если use integer (см. "Целочисленная арифметика") активен, используются знакомые целые числа C (арифметический сдвиг), в противном случае — беззнаковые целые числа C (логический сдвиг), даже для отрицательных операндов. При арифметическом сдвиге вправо знаковый бит дублируется слева, при логическом сдвиге слева вставляются нули.

В любом случае, реализация не будет генерировать результаты, превышающие размер целочисленного типа, с которым был создан Perl (32 бита или 64 бита).

Сдвиг на отрицательное количество битов означает обратный сдвиг: сдвиг влево становится сдвигом вправо, сдвиг вправо становится сдвигом влево. Это отличается от C, где отрицательный сдвиг не определён.

Сдвиг на большее количество битов, чем размер целых чисел, в большинстве случаев даёт ноль (все биты отпадают), за исключением случая use integer, когда при правом сдвиге отрицательного операнда получается -1. Это отличается от C, где сдвиг на слишком большое количество битов не определён. Типичное поведение в C — "сдвиг по модулю размера слова", так что, например,

1 >> 64 == 1 >> (64 % 64) == 1 >> 0 == 1  # Common C behavior.

но это полностью случайность.

Если вы устали от подчинения нативным целым числам вашей платформы, то pragma use bigint элегантно обходит эту проблему:

print 20 << 20;  # 20971520
print 20 << 40;  # 5120 on 32-bit machines,
                 # 21990232555520 on 64-bit machines
use bigint;
print 20 << 100; # 25353012004564588029934064107520

Именованные унарные операторы

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

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

chdir $foo    || die;       # (chdir $foo) || die
chdir($foo)   || die;       # (chdir $foo) || die
chdir ($foo)  || die;       # (chdir $foo) || die
chdir +($foo) || die;       # (chdir $foo) || die

но, поскольку "*" имеет более высокий приоритет, чем именованные операторы:

chdir $foo * 20;    # chdir ($foo * 20)
chdir($foo) * 20;   # (chdir $foo) * 20
chdir ($foo) * 20;  # (chdir $foo) * 20
chdir +($foo) * 20; # chdir ($foo * 20)

rand 10 * 20;       # rand (10 * 20)
rand(10) * 20;      # (rand 10) * 20
rand (10) * 20;     # (rand 10) * 20
rand +(10) * 20;    # rand (10 * 20)

Что касается приоритета, операторы проверки файлов, такие как -f, -M, и т.д., обрабатываются как именованные унарные операторы, но они не следуют этому правилу функциональных скобок. Это означает, что, например, -f($file).".bak" эквивалентно -f "$file.bak".

См. также "Элементы и операторы списков (влево)".

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

Операторы Perl, которые возвращают истину или ложь, обычно возвращают значения, которые можно безопасно использовать как числа. Например, операторы сравнения в этом разделе и операторы равенства в следующем возвращают 1 для истины и специальную версию пустой строки, "", которая считается нулём, но исключается из предупреждений о некорректных числовых преобразованиях, так же как и "0 but true".

Бинарный оператор "<" возвращает истину, если левый аргумент численно меньше правого аргумента.

Бинарный оператор ">" возвращает истину, если левый аргумент численно больше правого аргумента.

Бинарный оператор "<=" возвращает истину, если левый аргумент численно меньше или равен правому аргументу.

Бинарный оператор ">=" возвращает истину, если левый аргумент численно больше или равен правому аргументу.

Бинарный оператор "lt" возвращает истину, если левый аргумент лексикографически меньше правого аргумента.

Бинарный оператор "gt" возвращает истину, если левый аргумент лексикографически больше правого аргумента.

Бинарный оператор "le" возвращает истину, если левый аргумент лексикографически меньше или равен правому аргументу.

Бинарный оператор "ge" возвращает истину, если левый аргумент лексикографически больше или равен правому аргументу.

Последовательность операторов сравнения, например, "$x < $y <= $z", выполняет цепочку сравнений, как описано выше в разделе "Приоритет и ассоциативность операторов". Следите за тем, что они не образуют цепочку с операторами равенства, которые имеют более низкий приоритет.

Операторы равенства

Бинарный оператор "==" возвращает истину, если левый аргумент численно равен правому аргументу.

Бинарный оператор "!=" возвращает истину, если левый аргумент численно не равен правому аргументу.

Бинарный оператор "eq" возвращает истину, если левый аргумент лексикографически равен правому аргументу.

Бинарный оператор "ne" возвращает истину, если левый аргумент лексикографически не равен правому аргументу.

Последовательность вышеперечисленных операторов равенства, таких как "$x == $y == $z", выполняет цепочку сравнений, как описано выше в разделе "Приоритет и ассоциативность операторов". Следите за тем, что они не образуют цепочку с операторами сравнения, которые имеют более высокий приоритет.

Бинарный оператор "<=>" возвращает -1, 0 или 1 в зависимости от того, является ли левый аргумент численно меньше, равен или больше правого аргумента. Если ваша платформа поддерживает NaN (не числа) как числовые значения, их использование с оператором "<=>" возвращает undef. NaN не "<", "==", ">", "<=" или ">=" что-либо (даже NaN), поэтому эти 5 возвращают ложь. NaN != NaN возвращает истину, как и NaN != любое другое значение. Если ваша платформа не поддерживает NaN (NaN), то NaN — это просто строка с числовым значением 0.

$ perl -le '$x = "NaN"; print "No NaN support here" if $x == $x'
$ perl -le '$x = "NaN"; print "NaN support here" if $x != $x'

(Обратите внимание, что pragmas bigint, bigrat и bignum все поддерживают "NaN".)

Бинарный оператор "cmp" возвращает -1, 0 или 1 в зависимости от того, является ли левый аргумент лексикографически меньше, равен или больше правого аргумента.

Бинарный оператор "~~" выполняет умное соответствие между своими аргументами. Умное соответствие описано в следующем разделе.

Двусторонние операторы упорядочения "<=>" и "cmp", а также оператор умного соответствия "~~" не являются ассоциативными относительно друг друга и относительно операторов равенства того же приоритета.

"lt", "le", "ge", "gt" и "cmp" используют порядок сортировки, заданный текущим LC_COLLATE языковым стандартом, если в силе форма use locale, включающая порядок сортировки. См. perllocale. Не смешивайте их с Юникодом, используйте только с кодировками 8-битных устаревших языковых стандартов. Модули Unicode::Collate и Unicode::Collate::Locale предлагают гораздо более мощные решения для проблем сортировки.

Для выполнения сравнения без учёта регистра используйте функцию "fc" в perlfunc преобразования регистра, доступную в Perl v5.16 или более поздних версиях:

if ( fc($x) eq fc($y) ) { ... }

Оператор типа объекта

Бинарный оператор isa возвращает true, когда левое операнд является экземпляром класса (или подкласса, производного от этого класса), указанного правым операндом. Если левое операнд не определено, не является экземпляром объекта, благословленного классом или не является производным от класса, указанного правым операндом, оператор возвращает false. Правый операнд может указывать класс либо как ключевое слово, либо как скалярное выражение, которое возвращает имя класса в виде строки:

if( $obj isa Some::Class ) { ... }

if( $obj isa "Different::Class" ) { ... }
if( $obj isa $name_of_class ) { ... }

Это экспериментальная функция, доступная начиная с Perl 5.31.6 при включении use feature 'isa'. Она генерирует предупреждение в категории experimental::isa.

Оператор Smartmatch

Впервые доступный в Perl 5.10.1 (версия 5.10.0 имела другое поведение), бинарный оператор ~~ выполняет "умное сопоставление" между своими операндами. Это в основном используется неявно в конструкции when описанной в perlsyn, хотя не все when-записи вызывают оператор smartmatch. В отличие от всех других операторов Perl, оператор smartmatch может рекурсировать. Оператор smartmatch является экспериментальным, и его поведение может измениться.

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

Оператор ~~ сравнивает свои операнды "полиморфно", определяя, как их сравнивать в зависимости от их фактических типов (числовой, строковый, массивный, хэшовый и т. д.). Как и операторы равенства, с которыми он имеет одинаковый приоритет, оператор ~~ возвращает 1 для true и "" для false. Его часто лучше произносить вслух как "в", "внутри", или "содержит", так как левый операнд часто ищется внутри правого операнда. Это делает порядок операндов в операторе smartmatch часто обратным порядку регулярного оператора сопоставления. Другими словами, "меньшая" вещь обычно размещается в левом операнде, а "большая" — в правом.

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

Left      Right      Description and pseudocode
===============================================================
Any       undef      check whether Any is undefined
               like: !defined Any

Any       Object     invoke ~~ overloading on Object, or die

Right operand is an ARRAY:

Left      Right      Description and pseudocode
===============================================================
ARRAY1    ARRAY2     recurse on paired elements of ARRAY1 and ARRAY2[2]
               like: (ARRAY1[0] ~~ ARRAY2[0])
                       && (ARRAY1[1] ~~ ARRAY2[1]) && ...
HASH      ARRAY      any ARRAY elements exist as HASH keys
               like: grep { exists HASH->{$_} } ARRAY
Regexp    ARRAY      any ARRAY elements pattern match Regexp
               like: grep { /Regexp/ } ARRAY
undef     ARRAY      undef in ARRAY
               like: grep { !defined } ARRAY
Any       ARRAY      smartmatch each ARRAY element[3]
               like: grep { Any ~~ $_ } ARRAY

Right operand is a HASH:

Left      Right      Description and pseudocode
===============================================================
HASH1     HASH2      all same keys in both HASHes
               like: keys HASH1 ==
                        grep { exists HASH2->{$_} } keys HASH1
ARRAY     HASH       any ARRAY elements exist as HASH keys
               like: grep { exists HASH->{$_} } ARRAY
Regexp    HASH       any HASH keys pattern match Regexp
               like: grep { /Regexp/ } keys HASH
undef     HASH       always false (undef can't be a key)
               like: 0 == 1
Any       HASH       HASH key existence
               like: exists HASH->{Any}

Right operand is CODE:

Left      Right      Description and pseudocode
===============================================================
ARRAY     CODE       sub returns true on all ARRAY elements[1]
               like: !grep { !CODE->($_) } ARRAY
HASH      CODE       sub returns true on all HASH keys[1]
               like: !grep { !CODE->($_) } keys HASH
Any       CODE       sub passed Any returns true
               like: CODE->(Any)

Правый операнд — это регулярное выражение:

Left      Right      Description and pseudocode
===============================================================
ARRAY     Regexp     any ARRAY elements match Regexp
               like: grep { /Regexp/ } ARRAY
HASH      Regexp     any HASH keys match Regexp
               like: grep { /Regexp/ } keys HASH
Any       Regexp     pattern match
               like: Any =~ /Regexp/

Other:

Left      Right      Description and pseudocode
===============================================================
Object    Any        invoke ~~ overloading on Object,
                     or fall back to...

Any       Num        numeric equality
                like: Any == Num
Num       nummy[4]    numeric equality
                like: Num == nummy
undef     Any        check whether undefined
                like: !defined(Any)
Any       Any        string equality
                like: Any eq Any

Примечания:

1. Пустые хэши или массивы совпадают.
2. То есть, каждый элемент smartmatch соответствует элементу с тем же индексом в другом массиве.[3]
3. Если обнаружена циклическая ссылка, возвращается ссылочная эквивалентность.
4. Либо фактическое число, либо строка, похожая на число.

Оператор smartmatch неявно удаляет ссылку на любой неблагословленный хэш или массив, поэтому записи HASH и ARRAY применяются в этих случаях. Для благословленных ссылок применяются записи Object. При smartmatch с хэшами учитываются только ключи хэша, а не значения.

Запись кода "like" не всегда является точным соответствием. Например, оператор smartmatch выполняет короткое замыкание, когда это возможно, но grep этого не делает. Также grep в скалярном контексте возвращает количество совпадений, а ~~ возвращает только true или false.

В отличие от большинства операторов, оператор smartmatch знает, как обращаться со undef особенно:

use v5.10.1;
@array = (1, 2, 3, undef, 4, 5);
say "some elements undefined" if undef ~~ @array;

Каждый операнд рассматривается в изменённом скалярном контексте, модификация заключается в том, что массивы и хэши передаются оператору по ссылке, который неявно удаляет ссылку на них. Оба элемента каждой пары совпадают:

use v5.10.1;

my %hash = (red    => 1, blue   => 2, green  => 3,
            orange => 4, yellow => 5, purple => 6,
            black  => 7, grey   => 8, white  => 9);

my @array = qw(red blue green);

say "some array elements in hash keys" if  @array ~~  %hash;
say "some array elements in hash keys" if \@array ~~ \%hash;

say "red in array" if "red" ~~  @array;
say "red in array" if "red" ~~ \@array;

say "some keys end in e" if /e$/ ~~  %hash;
say "some keys end in e" if /e$/ ~~ \%hash;

Два массива smartmatch, если каждый элемент в первом массиве smartmatch (то есть, "в") соответствующий элемент во втором массиве, рекурсивно.

use v5.10.1;
my @little = qw(red blue green);
my @bigger = ("red", "blue", [ "orange", "green" ] );
if (@little ~~ @bigger) {  # true!
    say "little is contained in bigger";
}

Поскольку оператор smartmatch рекурсивно обрабатывает вложенные массивы, это по-прежнему указывает, что "красный" находится в массиве.

use v5.10.1;
my @array = qw(red blue green);
my $nested_array = [[[[[[[ @array ]]]]]]];
say "red in array" if "red" ~~ $nested_array;

Если два массива smartmatch друг друга, то они являются глубокими копиями значений друг друга, как показывает этот пример:

use v5.12.0;
my @a = (0, 1, 2, [3, [4, 5], 6], 7);
my @b = (0, 1, 2, [3, [4, 5], 6], 7);

if (@a ~~ @b && @b ~~ @a) {
    say "a and b are deep copies of each other";
}
elsif (@a ~~ @b) {
    say "a smartmatches in b";
}
elsif (@b ~~ @a) {
    say "b smartmatches in a";
}
else {
    say "a and b don't smartmatch each other at all";
}

Если вы установите $b[3] = 4, то вместо сообщения "a и b являются глубокими копиями друг друга", теперь сообщается, что "b smartmatches in a". Это потому, что соответствующая позиция в @a содержит массив, который (в конечном счете) содержит 4.

Smartmatch одного хэша с другим сообщает, содержат ли оба одинаковые ключи, без учета значений этих полей. Это можно использовать для проверки, имеют ли две записи одинаковые имена полей, не заботясь о значениях этих полей. Например:

use v5.10.1;
sub make_dogtag {
    state $REQUIRED_FIELDS = { name=>1, rank=>1, serial_num=>1 };

    my ($class, $init_fields) = @_;

    die "Must supply (only) name, rank, and serial number"
        unless $init_fields ~~ $REQUIRED_FIELDS;

    ...
}

Однако, это имеет смысл только если $init_fields является ссылкой на хэш. Условие $init_fields ~~ $REQUIRED_FIELDS также позволяет строкам "name", "rank", "serial_num" а также любой ссылке на массив, содержащей "name" или "rank" или "serial_num" в любом месте, пройти без изменений.

Оператор smartmatch чаще всего используется в качестве неявного оператора в when-записи. Смотрите раздел "Условные операторы" в perlsyn.

Smartmatch объектов

Чтобы избежать зависимости от внутреннего представления объекта, если правым операндом smartmatch является объект, который не перегружает оператор ~~, он генерирует исключение "Smartmatching a non-overloaded object breaks encapsulation". Дело в том, что нет смысла изучать, является ли что-то "внутри" объекта. Все это является недопустимым для объектов без перегрузки ~~:

 %hash ~~ $object
    42 ~~ $object
"fred" ~~ $object

Однако, вы можете изменить способ smartmatch объекта, перегрузив оператор ~~. Это разрешено для расширения обычных семантик smartmatch. Для объектов, которые имеют перегрузку ~~ см. overload.

Использование объекта в качестве левого операнда разрешено, но не очень полезно. Правила smartmatch имеют приоритет над перегрузкой, поэтому даже если объект в левом операнде имеет перегрузку smartmatch, это будет проигнорировано. Левый операнд, являющийся объектом без перегрузки, использует строковое или числовое сравнение того, что возвращает оператор ref. Это означает, что

$object ~~ X

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

$object ~~ $number          ref($object) == $number
$object ~~ $string          ref($object) eq $string

Например, это сообщает, что обработчик пахнет IOish (но пожалуйста, не делайте этого на самом деле!):

use IO::Handle;
my $fh = IO::Handle->new();
if ($fh ~~ /\bIO\b/) {
    say "handle smells IOish";
}

Это потому, что он обрабатывает $fh как строку, как "IO::Handle=GLOB(0x8039e0)", а затем выполняет сопоставление с образцом.

Побитовое И

Бинарный оператор "&" возвращает операнды, побитовое И которых. Хотя в настоящее время предупреждение не выводится, результат не определён, когда эта операция выполняется с операндами, которые не являются числами (см. "Целочисленные арифметические операции") или битовыми строками (см. "Битовые операции со строками").

Обратите внимание, что "&" имеет более низкий приоритет, чем операторы отношений, поэтому, например, скобки необходимы в тесте, таком как

print "Even\n" if ($x & 1) == 0;

Если функция "битовая" включена через use feature 'bitwise' или use v5.28, то этот оператор всегда обрабатывает свои операнды как числа. До Perl 5.28 эта функция генерировала предупреждение в категории "experimental::bitwise".

Побитовое ИЛИ и Побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ

Бинарный оператор "|" возвращает операнды, побитовое ИЛИ которых.

Бинарный оператор "^" возвращает операнды, побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ которых.

Хотя в настоящее время предупреждение не выводится, результат не определён, когда эти операции выполняются с операндами, которые не являются числами (см. "Целочисленные арифметические операции") или битовыми строками (см. "Битовые операции со строками").

Обратите внимание, что "|" и "^" имеют более низкий приоритет, чем операторы отношений, поэтому, например, скобки необходимы в тесте, таком как

print "false\n" if (8 | 2) != 10;

Если функция "битовая" включена через use feature 'bitwise' или use v5.28, то этот оператор всегда обрабатывает свои операнды как числа. До Perl 5.28 эта функция генерировала предупреждение в категории "experimental::bitwise".

Логическое И (стиль C)

Бинарный оператор "&&" выполняет операцию короткого замыкания логического И. То есть, если левый операнд ложный, правый операнд даже не оценивается. Скалярный или списковый контекст передается правому операнду, если он оценивается.

Логическое ИЛИ (стиль C)

Бинарный оператор "||" выполняет операцию короткого замыкания логического ИЛИ. То есть, если левый операнд истинный, правый операнд даже не оценивается. Скалярный или списковый контекст передается правому операнду, если он оценивается.

Логическое ИЛИ с проверкой определения

Хотя у него нет прямого аналога в C, оператор Perl // связан с его оператором C-стиля "или". На самом деле, он точно такой же, как ||, за исключением того, что он проверяет определённость левой части, а не её истинность. Таким образом, EXPR1 // EXPR2 возвращает значение EXPR1 если оно определено, в противном случае возвращается значение EXPR2. (EXPR1 оценивается в скалярном контексте, EXPR2 в контексте //). Обычно это тот же результат, что и defined(EXPR1) ? EXPR1 : EXPR2 (за исключением того, что форма тернарного оператора может использоваться как lvalue, в то время как EXPR1 // EXPR2 не может). Это очень полезно для предоставления значений по умолчанию для переменных. Если вам нужно проверить, определено ли хотя бы одно из $x и $y, используйте defined($x // $y).

Операторы ||, // и && возвращают последнее вычисленное значение (в отличие от C-стиля || и &&, которые возвращают 0 или 1). Таким образом, достаточно портативный способ определения домашнего каталога может быть:

$home =  $ENV{HOME}
      // $ENV{LOGDIR}
      // (getpwuid($<))[7]
      // die "You're homeless!\n";

В частности, это означает, что вы не должны использовать его для выбора между двумя агрегатами для присваивания:

@a = @b || @c;            # This doesn't do the right thing
@a = scalar(@b) || @c;    # because it really means this.
@a = @b ? @b : @c;        # This works fine, though.

В качестве альтернатив && и || при использовании в операторах управления потоком Perl предоставляет операторы and и or (см. ниже). Поведение короткого замыкания идентично. Однако приоритет операторов "and" и "or" значительно ниже, поэтому вы можете безопасно использовать их после оператора списка без скобок:

unlink "alpha", "beta", "gamma"
        or gripe(), next LINE;

С операторами в стиле C, которые можно было бы записать так:

unlink("alpha", "beta", "gamma")
        || (gripe(), next LINE);

Было бы ещё понятнее записать это так:

unless(unlink("alpha", "beta", "gamma")) {
    gripe();
    next LINE;
}

Использование "or" для присваивания вряд ли даст желаемый результат; см. ниже.

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

Бинарный оператор ".." — это оператор диапазона, который фактически представляет собой два разных оператора в зависимости от контекста. В контексте списка он возвращает список значений, считая (с шагом 1) от левого значения до правого. Если левое значение больше правого, возвращается пустой список. Оператор диапазона полезен для написания циклов foreach (1..10) и для выполнения операций срезов массивов. В текущей реализации при использовании оператора диапазона как выражения в циклах foreach не создаётся временный массив, но в более старых версиях Perl может быть выделено много памяти, если вы напишете что-то вроде этого:

for (1 .. 1_000_000) {
    # code
}

Оператор диапазона также работает со строками, используя магическое автоматическое инкрементирование, см. ниже.

В скалярном контексте оператор ".." возвращает булево значение. Оператор бистабилен, подобно триггеру, и эмулирует оператор диапазона строк (запятая) в sed, awk и различных редакторах. Каждый оператор ".." сохраняет собственное булево состояние, даже при вызовах подпрограммы, содержащей его. Он ложно до тех пор, пока его левый операнд ложен. Как только левый операнд становится истинным, оператор диапазона остаётся истинным до тех пор, пока правый операнд не станет истинным, ПОСЛЕ чего оператор диапазона снова становится ложным. Он не становится ложным до следующего вычисления оператора диапазона. Он может проверить правый операнд и стать ложным в том же вычислении, в котором он стал истинным (как в awk), но он всё равно возвращает истинное значение один раз. Если вы не хотите, чтобы он проверял правый операнд до следующего вычисления, как в sed, используйте три точки ("...") вместо двух. Во всех остальных отношениях, "..." ведет себя так же, как и "..".

Правый операнд не вычисляется, пока оператор находится в состоянии «ложно», а левый операнд не вычисляется, пока оператор находится в состоянии «истина». Приоритет немного ниже, чем у || и &&. Возвращаемое значение — это либо пустая строка для ложного значения, либо номер последовательности (начиная с 1) для истинного значения. Номер последовательности сбрасывается для каждого диапазона. Последний номер последовательности в диапазоне имеет строку "E0", добавленную к нему, что не влияет на его числовое значение, но даёт вам что-то для поиска, если вы хотите исключить конечную точку. Вы можете исключить начальную точку, ожидая, пока номер последовательности не станет больше 1.

Если какой-либо операнд скалярного оператора ".." является константным выражением, этот операнд считается истинным, если он равен (==) текущему номеру строки ввода (переменная $.).

Для точности, сравнение фактически выполняется по формуле int(EXPR) == int(EXPR), но это проблема только при использовании выражений с плавающей точкой; при неявном использовании $., как описано в предыдущем абзаце, сравнение выполняется по формуле int(EXPR) == int($.), что является проблемой только тогда, когда $. установлено в значение с плавающей точкой, и вы не читаете данные из файла. Кроме того, "span" .. "spat" или 2.18 .. 3.14 не дадут желаемого результата в скалярном контексте, поскольку каждый из операндов оценивается с использованием своего целочисленного представления.

Примеры:

В качестве скалярного оператора:

if (101 .. 200) { print; } # print 2nd hundred lines, short for
                           #  if ($. == 101 .. $. == 200) { print; }

next LINE if (1 .. /^$/);  # skip header lines, short for
                           #   next LINE if ($. == 1 .. /^$/);
                           # (typically in a loop labeled LINE)

s/^/> / if (/^$/ .. eof());  # quote body

# parse mail messages
while (<>) {
    $in_header =   1  .. /^$/;
    $in_body   = /^$/ .. eof;
    if ($in_header) {
        # do something
    } else { # in body
        # do something else
    }
} continue {
    close ARGV if eof;             # reset $. each file
}

Вот простой пример, иллюстрирующий разницу между двумя операторами диапазона:

@lines = ("   - Foo",
          "01 - Bar",
          "1  - Baz",
          "   - Quux");

foreach (@lines) {
    if (/0/ .. /1/) {
        print "$_\n";
    }
}

Эта программа будет выводить только строку, содержащую «Bar». Если оператор диапазона изменить на ..., она также выведет строку «Baz».

И теперь некоторые примеры в качестве оператора списка:

for (101 .. 200) { print }      # print $_ 100 times
@foo = @foo[0 .. $#foo];        # an expensive no-op
@foo = @foo[$#foo-4 .. $#foo];  # slice last 5 items

Так как каждый операнд оценивается в целочисленной форме, 2.18 .. 3.14 вернёт два элемента в контексте списка.

@list = (2.18 .. 3.14); # same as @list = (2 .. 3);

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

  • За исключением одного случая (ниже), если обе строки похожи на числа для Perl, магическое инкрементирование не будет применено, и строки будут обработаны как числа (точнее, целые числа) вместо строк.

    Например, "-2".."2" то же самое, что и -2..2, а "2.18".."3.14" даёт 2, 3.

  • Исключение из вышеуказанного правила — когда строка слева начинается с 0 и имеет длину более одного символа. В этом случае магическое инкрементирование будет применено, даже если строки вроде "01" обычно интерпретируются Perl как числа.

    Например, "01".."04" даёт "01", "02", "03", "04", а "00".."-1" даёт "00" до "99" — это может показаться неожиданным, но см. следующие правила, объясняющие, почему это работает именно так. Для получения дат с ведущими нулями вы можете сказать:

    @z2 = ("01" .. "31");
    print $z2[$mday];

    Если вы хотите принудительно интерпретировать строки как числа, вы можете сказать

    @numbers = ( 0+$first .. 0+$last );
  • Если начальное значение не является частью последовательности магического инкрементирования (то есть непустой строки, соответствующей /^[a-zA-Z]*[0-9]*\z/), возвращается только начальное значение.

    Например, "ax".."az" даёт "ax", "ay", "az", но "*x".."az" даёт только "*x".

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

    Например, вы можете сказать

    @alphabet = ("A" .. "Z");

    чтобы получить все обычные буквы английского алфавита или

    $hexdigit = (0 .. 9, "a" .. "f")[$num & 15];

    чтобы получить шестнадцатеричную цифру.

  • Если конечное значение не входит в последовательность, которая генерируется магическим инкрементированием, последовательность продолжается до тех пор, пока следующее значение не станет длиннее, чем указанное конечное значение. Если длина конечной строки меньше начальной, возвращается пустой список.

    Например, "a".."--" то же самое, что и "a".."zz", "0".."xx" даёт "0" до "99", а "aaa".."--" возвращает пустой список.

Начиная с Perl 5.26, оператор диапазона в контексте списка для строк работает как ожидается в рамках "use feature 'unicode_strings". В предыдущих версиях и вне этой функции он демонстрирует "Ошибку Unicode" в perlunicode: его поведение зависит от внутреннего кодирования конечной точки диапазона.

Поскольку магическое инкрементирование работает только с непустыми строками, соответствующими /^[a-zA-Z]*[0-9]*\z/, следующее вернёт только alpha:

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

Чтобы получить 25 традиционных строчных греческих букв, включая обе сигмы, вы можете использовать вместо этого:

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

Однако, так как существует много других строчных греческих символов, помимо этих, для сопоставления строчных греческих символов в регулярном выражении вы можете использовать шаблон /(?:(?=\p{Greek})\p{Lower})+/ (или экспериментальную функцию /(?[ \p{Greek} & \p{Lower} ])+/).

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

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

printf "I have %d dog%s.\n", $n,
        ($n == 1) ? "" : "s";

Скалярный или списочный контекст распространяется вниз на 2-й или 3-й аргумент, в зависимости от выбора.

$x = $ok ? $y : $z;  # get a scalar
@x = $ok ? @y : @z;  # get an array
$x = $ok ? @y : @z;  # oops, that's just a count!

Оператор можно присвоить, если оба 2-й и 3-й аргументы являются допустимыми левыми значениями (то есть к ним можно присвоить значение):

($x_or_y ? $x : $y) = $z;

Поскольку этот оператор создаёт присваиваемый результат, использование присваивания без скобок приведёт к проблемам. Например, это:

$x % 2 ? $x += 10 : $x += 2

На самом деле означает это:

(($x % 2) ? ($x += 10) : $x) += 2

А не это:

($x % 2) ? ($x += 10) : ($x += 2)

Это, вероятно, лучше записать проще:

$x += ($x % 2) ? 10 : 2;

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

"=" — это обычный оператор присваивания.

Операторы присваивания работают, как в C. То есть,

$x += 2;

эквивалентно

$x = $x + 2;

хотя и без дублирования побочных эффектов, которые может вызвать обращение к левому значению, таких как tie(). Аналогичным образом работают и другие операторы присваивания. Признаются следующие:

**=    +=    *=    &=    &.=    <<=    &&=
       -=    /=    |=    |.=    >>=    ||=
       .=    %=    ^=    ^.=           //=
             x=

Хотя они сгруппированы по семействам, все они имеют приоритет присваивания. Эти комбинированные операторы присваивания могут работать только со скалярами, в то время как обычный оператор присваивания может присваивать значения массивам, хэшам, спискам и даже ссылкам. (См. "Контекст" и "Конструкторы списковых значений" в perldata, и "Присваивание ссылок" в perlref.)

В отличие от C, скалярный оператор присваивания создаёт допустимое левое значение. Модификация присваивания эквивалентна выполнению присваивания, а затем модификации переменной, которой присваивалось значение. Это полезно для модификации копии чего-либо, например, так:

($tmp = $global) =~ tr/13579/24680/;

Хотя начиная с версии 5.14, это также можно сделать так:

use v5.14;
$tmp = ($global =~  tr/13579/24680/r);

Аналогично,

($x += 2) *= 3;

эквивалентно

$x += 2;
$x *= 3;

Также, список присваивания в списочном контексте создаёт список левых значений, которым присваиваются значения, а список присваивания в скалярном контексте возвращает количество элементов, созданных выражением справа от оператора присваивания.

Три точки у битовых операторов присваивания (&.= |.= ^.=) появились в Perl 5.22. См. "Битовые строковые операторы".

Оператор запятой

Бинарный оператор "," — это оператор запятой. В скалярном контексте он вычисляет свой левый операнд, отбрасывает это значение, затем вычисляет свой правый операнд и возвращает это значение. Это то же самое, что и оператор запятой в C.

В контексте списка это просто разделитель аргументов списка, и вставляет оба своих аргумента в список. Эти аргументы также оцениваются слева направо.

Оператор => (иногда произносится как «жирная запятая») является синонимом запятой, за исключением того, что он заставляет слово слева интерпретироваться как строку, если оно начинается с буквы или подчеркивания и состоит только из букв, цифр и подчеркиваний. Это включает операнды, которые в противном случае могли бы интерпретироваться как операторы, константы, одночисловые v-строки или вызовы функций. Если вы сомневаетесь в этом поведении, левый операнд можно явно заключить в кавычки.

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

Например:

use constant FOO => "something";

my %h = ( FOO => 23 );

эквивалентно:

my %h = ("FOO", 23);

Это НЕ:

my %h = ("something", 23);

Оператор => полезен для документирования соответствия между ключами и значениями в хешах и другими парными элементами в списках.

%hash = ( $key => $value );
login( $username => $password );

Специальное поведение цитирования игнорирует приоритет и, следовательно, может применяться к части левого операнда:

print time.shift => "bbb";

Этот пример выводит что-то вроде "1314363215shiftbbb", потому что оператор => неявным образом заключает в кавычки shift сразу слева, игнорируя тот факт, что time.shift является целым левым операндом.

Операторы списков (Вправо)

С правой стороны оператора списка запятая имеет очень низкий приоритет, поэтому она управляет всеми выражениями, разделенными запятыми, которые там встречаются. Единственными операторами с более низким приоритетом являются логические операторы "and", "or", и "not", которые можно использовать для оценки вызовов операторов списка без скобок:

open HANDLE, "< :encoding(UTF-8)", "filename"
    or die "Can't open: $!\n";

Однако некоторым людям кажется, что такой код сложнее читать, чем написанный со скобками:

open(HANDLE, "< :encoding(UTF-8)", "filename")
    or die "Can't open: $!\n";

в этом случае вы можете просто использовать более привычный оператор "||".

open(HANDLE, "< :encoding(UTF-8)", "filename")
    || die "Can't open: $!\n";

См. также обсуждение операторов списков в "Операторы списков и терминов (Влево)".

Логическое отрицание

Унарный оператор "not" возвращает логическое отрицание выражения справа от него. Это эквивалентно "!", за исключением очень низкого приоритета.

Логическое И

Бинарный оператор "and" возвращает логическое конъюнкцию двух окружающих выражений. Это эквивалентно &&, за исключением очень низкого приоритета. Это означает, что он выполняет короткое замыкание: правое выражение вычисляется только если левое выражение истинно.

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

Бинарный оператор "or" возвращает логическое дизъюнкцию двух окружающих выражений. Это эквивалентно ||, за исключением очень низкого приоритета. Это делает его полезным для управления потоком:

print FH $data              or die "Can't write to FH: $!";

Это означает, что он выполняет короткое замыкание: правое выражение вычисляется только если левое выражение ложно. Из-за его приоритета вы должны быть осторожны, чтобы избежать использования его в качестве замены оператора ||. Обычно он лучше работает для управления потоком, чем в присваиваниях:

$x = $y or $z;              # bug: this is wrong
($x = $y) or $z;            # really means this
$x = $y || $z;              # better written this way

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

@info = stat($file) || die;     # oops, scalar sense of stat!
@info = stat($file) or die;     # better, now @info gets its due

Впрочем, вы всегда можете использовать скобки.

Бинарный оператор "xor" возвращает исключающее ИЛИ двух окружающих выражений. Он не может выполнить короткое замыкание (конечно).

Нет оператора с низким приоритетом для определенного ИЛИ.

Операторы C, отсутствующие в Perl

Вот что есть в C, чего нет в Perl:

унарный &

Оператор взятия адреса. (Но см. оператор "\" для получения ссылки.)

унарный *

Оператор разыменования адреса. (Префиксные операторы разыменования Perl имеют типы: $, @, %, и &.)

(TYPE)

Оператор приведения типов.

Операторы цитирования и похожие на цитирование

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

Customary  Generic        Meaning        Interpolates
    ''       q{}          Literal             no
    ""      qq{}          Literal             yes
    ``      qx{}          Command             yes*
            qw{}         Word list            no
    //       m{}       Pattern match          yes*
            qr{}          Pattern             yes*
             s{}{}      Substitution          yes*
            tr{}{}    Transliteration         no (but see below)
             y{}{}    Transliteration         no (but see below)
    <<EOF                 here-doc            yes*

    * unless the delimiter is ''.

Разделители, не являющиеся скобками, используют один и тот же символ спереди и сзади, но все четыре типа ASCII скобок (круглые, угловые, квадратные, фигурные) вложены, что означает, что

q{foo{bar}baz}

то же самое, что

'foo{bar}baz'

Однако обратите внимание, что это не всегда работает для цитирования кода Perl:

$s = q{ if($x eq "}") ... }; # WRONG

является синтаксической ошибкой. Модуль Text::Balanced (стандартный начиная с версии 5.8, и из CPAN до этого) может сделать это правильно.

Между оператором и символами кавычек может (и в некоторых случаях должен) быть пробел, за исключением случаев, когда # используется в качестве символа кавычек. q#foo# разбирается как строка foo, а q #foo# является оператором q за которым следует комментарий. Его аргумент будет взят из следующей строки. Это позволяет вам написать:

s {foo}  # Replace foo
  {bar}  # with bar.

Случаи, когда пробелы должны использоваться, возникают, когда символ кавычек является символом слова (что означает, что он соответствует /\w/):

q XfooX # Works: means the string 'foo'
qXfooX  # WRONG!

Следующие последовательности экранирования доступны в конструкциях, которые интерполируют, и в транслитерациях, разделители которых не являются одинарными кавычками ("'").

Sequence     Note  Description
\t                  tab               (HT, TAB)
\n                  newline           (NL)
\r                  return            (CR)
\f                  form feed         (FF)
\b                  backspace         (BS)
\a                  alarm (bell)      (BEL)
\e                  escape            (ESC)
\x{263A}     [1,8]  hex char          (example shown: SMILEY)
\x1b         [2,8]  restricted range hex char (example: ESC)
\N{name}     [3]    named Unicode character or character sequence
\N{U+263D}   [4,8]  Unicode character (example: FIRST QUARTER MOON)
\c[          [5]    control char      (example: chr(27))
\o{23072}    [6,8]  octal char        (example: SMILEY)
\033         [7,8]  restricted range octal char  (example: ESC)
[1]

Результат — символ, заданный шестнадцатеричным числом в фигурных скобках. Подробности о символе см. в "[8]" ниже.

В фигурных скобках допустимы только шестнадцатеричные цифры. При обнаружении недопустимого символа будет выведено предупреждение, а недопустимый символ и все последующие символы (допустимые или недопустимые) в фигурных скобках будут отброшены.

Если между фигурными скобками нет допустимых цифр, генерируемый символ — символ NULL (\x{00}). Однако явное пустое выражение в фигурных скобках (\x{}) не вызовет предупреждения (на данный момент).

[2]

Результат — символ, заданный шестнадцатеричным числом в диапазоне от 0x00 до 0xFF. Подробности о символе см. в "[8]" ниже.

После \x допустимы только шестнадцатеричные цифры. Если после \x следует меньше двух допустимых цифр, любые допустимые цифры будут дополнены нулями слева. Это означает, что \x7 будет интерпретироваться как \x07, а одиночное "\x" — как \x00. За исключением конца строки, наличие менее двух допустимых цифр приведет к появлению предупреждения. Обратите внимание, что, хотя предупреждение гласит, что недопустимый символ игнорируется, он игнорируется только как часть escape-последовательности и по-прежнему используется как последующий символ в строке. Например:

Original    Result    Warns?
"\x7"       "\x07"    no
"\x"        "\x00"    no
"\x7q"      "\x07q"   yes
"\xq"       "\x00q"   yes
[3]

Результат — символ или последовательность символов Unicode, заданные значением name. См. charnames.

[4]

\N{U+hexadecimal number} означает символ Unicode, у которого код Unicode — шестнадцатеричное число.

[5]

Символ, следующий за \c, отображается как другой символ, как показано в таблице:

Sequence   Value
  \c@      chr(0)
  \cA      chr(1)
  \ca      chr(1)
  \cB      chr(2)
  \cb      chr(2)
  ...
  \cZ      chr(26)
  \cz      chr(26)
  \c[      chr(27)
                    # See below for chr(28)
  \c]      chr(29)
  \c^      chr(30)
  \c_      chr(31)
  \c?      chr(127) # (on ASCII platforms; see below for link to
                    #  EBCDIC discussion)

Другими словами, это символ, код которого был побитовым XOR'ом с 64, и преобразован к верхнему регистру. \c? — это DELETE на платформах ASCII, так как ord("?") ^ 64 равно 127, а \c@ — это NULL, потому что ord от "@" равно 64, а побитовый XOR с самим собой даёт 0.

Кроме того, \c\X даёт chr(28) . "X" для любого X, но не может стоять в конце строки, потому что обратная косая черта будет интерпретирована как экранирование закрывающей кавычки.

На платформах ASCII результирующие символы из приведенного выше списка представляют собой полный набор управляющих символов ASCII. Это не так на платформах EBCDIC; для полного обсуждения различий между ASCII и EBCDIC платформами см. "OPERATOR DIFFERENCES" в perlebcdic.

Использование любого другого символа после "c", кроме перечисленных выше, не рекомендуется. Начиная с Perl v5.20, разрешены только печатные символы ASCII без левой фигурной скобки "{". Для любого разрешенного символа значение получается путём побитового XOR'a с седьмым битом (который равен 64), и если включена настройка, выводится предупреждение. Использование недопустимых символов приводит к ошибке.

Для получения независимых от платформы управляющих символов можно использовать \N{...}.

[6]

Результат — символ, заданный восьмеричным числом в фигурных скобках. Подробности о символе см. в "[8]" ниже.

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

[7]

Результат — символ, заданный трехзначным восьмеричным числом в диапазоне от 000 до 777 (но лучше не использовать значения выше 077, см. следующий абзац). Подробности о символе см. в "[8]" ниже.

В некоторых контекстах допускается использование 2 или даже 1 цифры, но любое использование без ровно трех цифр, первой из которых является ноль, может привести к непредвиденным результатам. (Например, в регулярном выражении это может быть спутано со ссылкой на обратную ссылку; см. "Octal escapes" в perlrebackslash.) Начиная с Perl 5.14, можно использовать \o{}, что устраняет все эти проблемы. В противном случае лучше использовать эту конструкцию только для порядковых номеров \077 и ниже, помня о необходимости дополнения до трех цифр нулями слева. Для больших порядковых номеров используйте \o{}, или преобразуйте их в другое представление, например, в шестнадцатеричное и используйте \N{U+} (что портабельно между платформами с различными наборами символов) или \x{}.

[8]

Несколько конструкций выше задают символ с помощью числа. Это число указывает позицию символа в кодировке набора символов (индексируется с 0). Это синонимично называется порядковым номером, позицией кода или кодовым значением. Perl работает на платформах, которые в настоящее время имеют собственные кодировки ASCII/Latin1 или EBCDIC, каждая из которых позволяет указать 256 символов. В общем случае, если число составляет 255 (0xFF, 0377) или меньше, Perl интерпретирует его в кодировке собственной платформы. Если число составляет 256 (0x100, 0400) или больше, Perl интерпретирует его как код Unicode, и результат — соответствующий символ Unicode. Например, \x{50} и \o{120} — это число 80 в десятичной системе, которое меньше 256, поэтому число интерпретируется в кодировке символов собственной платформы. В ASCII символом в 80-й позиции (индексируется с 0) является буква "P", а в EBCDIC — символ амперсанда "&". \x{100} и \o{400} — это 256 в десятичной системе, поэтому число интерпретируется как код Unicode независимо от кодировки собственной платформы. Название символа в 256-й позиции (индексируется с 0) в Unicode — LATIN CAPITAL LETTER A WITH MACRON.

Исключение из приведенного выше правила заключается в том, что \N{U+hex number} всегда интерпретируется как код Unicode, поэтому \N{U+0050} равно "P" даже на платформах EBCDIC.

ПРИМЕЧАНИЕ: В отличие от C и других языков, в Perl нет \v escape-последовательности для вертикальной табуляции (VT, которая равна 11 в ASCII и EBCDIC), но можно использовать \N{VT}, \ck, \N{U+0b}, или \x0b. (\v имеет значение в шаблонах регулярных выражений в Perl, см. perlre.)

Следующие escape-последовательности доступны в конструкциях, выполняющих интерполяцию, но не в транслитерациях.

\l          lowercase next character only
\u          titlecase (not uppercase!) next character only
\L          lowercase all characters till \E or end of string
\U          uppercase all characters till \E or end of string
\F          foldcase all characters till \E or end of string
\Q          quote (disable) pattern metacharacters till \E or
            end of string
\E          end either case modification or quoted section
            (whichever was last seen)

См. "quotemeta" в perlfunc для точного определения символов, которые экранируются \Q.

\L, \U, \F, и \Q могут использоваться совместно, в этом случае вам потребуется один \E для каждого. Например:

say"This \Qquoting \ubusiness \Uhere isn't quite\E done yet,\E is it?";
This quoting\ Business\ HERE\ ISN\'T\ QUITE\ done\ yet\, is it?

Если активна форма use locale, включающая LC_CTYPE (см. perllocale), таблица преобразования регистров, используемая \l, \L, \u, и \U, берется из текущего языка. Если используется Unicode (например, \N{} или коды символов 0x100 и выше), таблица преобразования регистров, используемая \l, \L, \u, и \U, определена Unicode. Это означает, что преобразование регистра одного символа иногда может привести к последовательности нескольких символов. В use locale, \F дает те же результаты, что и \L во всех языках, кроме UTF-8, где используется определение Unicode.

Все системы используют виртуальный "\n" для представления разделителя строк, называемого "новая строка". Нет такого понятия, как неизменный физический символ новой строки. Существует лишь иллюзия, что операционная система, драйверы устройств, библиотеки C и Perl все вместе стремятся ее сохранить. Не все системы читают "\r" как ASCII CR и "\n" как ASCII LF. Например, на старых компьютерах Macintosh (до MacOS X) это было наоборот, а на системах без разделителя строк печать "\n" могла не выводить никаких данных. В общем случае, используйте "\n", когда вам нужна "новая строка" для вашей системы, но используйте литеральные ASCII-символы, когда нужен точный символ. Например, большинство сетевых протоколов ожидают и предпочитают CR+LF ("\015\012" или "\cM\cJ" для разделителей строк, и хотя они часто принимают только "\012", они редко допускают только "\015"). Если вы привыкнете использовать "\n" для сетевого взаимодействия, однажды вы можете обжечься.

Для конструкций, выполняющих интерполяцию, переменные, начинающиеся с "$" или "@", интерполируются. Индексированные переменные, такие как $a[3] или $href->{key}[0], также интерполируются, как и срезы массивов и хэшей. Но вызовы методов, такие как $obj->meth — нет.

Интерполяция массива или среза интерполирует элементы в порядке, разделенные значением $", что эквивалентно интерполяции join $", @array. "Пунктуационные" массивы, такие как @* обычно интерполируются только если имя заключено в фигурные скобки @{*}, но массивы @_, @+, и @- интерполируются даже без фигурных скобок.

Для строковых литералов с двойными кавычками экранирование из \Q применяется после интерполяции и обработки escape-последовательностей.

"abc\Qfoo\tbar$s\Exyz"

эквивалентно

"abc" . quotemeta("foo\tbar$s") . "xyz"

Для шаблонов операторов регулярных выражений (qr//, m// и s///), экранирование из \Q применяется после обработки интерполяции, но до обработки escape-последовательностей. Это позволяет шаблону совпадать буквально (кроме $ и @). Например, следующее соответствует:

'\s\t' =~ /\Q\s\t/

Поскольку $ или @ вызывают интерполяцию, вам нужно использовать что-то вроде /\Quser\E\@\Qhost/ для сопоставления их буквально.

Шаблоны также подвергаются дополнительной интерпретации как регулярное выражение. Это выполняется как второй этап, после интерполяции переменных, чтобы регулярные выражения могли быть включены в шаблон из переменных. Если этого не требуется, используйте \Q для интерполяции переменной буквально.

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

Операторы-квазицитаты для регулярных выражений

Вот операторы-квазицитаты, которые применяются к сопоставлению с образцом и связанным действиям.

qr/STRING/msixpodualn

Этот оператор приводит (и, возможно, компилирует) своё значение STRING в виде регулярного выражения. STRING интерполируется так же, как PATTERN в m/PATTERN/. Если используется разделитель "'", интерполяция переменных не выполняется. Возвращает значение Perl, которое может быть использовано вместо соответствующего /STRING/msixpodualn выражения. Возвращаемое значение — это нормализованная версия исходного шаблона. Оно магически отличается от строки, содержащей те же символы: ref(qr/x/) возвращает "Regexp"; однако, обращение к нему не определено (сейчас вы получаете нормализованную версию исходного шаблона, но это может измениться).

Например,

$rex = qr/my.STRING/is;
print $rex;                 # prints (?si-xm:my.STRING)
s/$rex/foo/;

эквивалентно

s/my.STRING/foo/is;

Результат может быть использован как подшаблон в поиске соответствия:

$re = qr/$pattern/;
$string =~ /foo${re}bar/;   # can be interpolated in other
                            # patterns
$string =~ $re;             # or used standalone
$string =~ /$re/;           # or this way

Поскольку Perl может скомпилировать шаблон в момент выполнения оператора qr(), использование qr() может принести преимущества в скорости в некоторых ситуациях, особенно если результат qr() используется автономно:

sub match {
    my $patterns = shift;
    my @compiled = map qr/$_/i, @$patterns;
    grep {
        my $success = 0;
        foreach my $pat (@compiled) {
            $success = 1, last if /$pat/;
        }
        $success;
    } @_;
}

Предварительная компиляция шаблона во внутреннее представление в момент qr() исключает необходимость повторной компиляции шаблона каждый раз, когда поиск соответствия /$pat/ пытается найти соответствие. (Perl имеет много других внутренних оптимизаций, но ни одна из них не будет вызвана в приведённом примере, если мы не используем оператор qr().)

Параметры (указанные следующими модификаторами) являются:

m   Treat string as multiple lines.
s   Treat string as single line. (Make . match a newline)
i   Do case-insensitive pattern matching.
x   Use extended regular expressions; specifying two
    x's means \t and the SPACE character are ignored within
    square-bracketed character classes
p   When matching preserve a copy of the matched string so
    that ${^PREMATCH}, ${^MATCH}, ${^POSTMATCH} will be
    defined (ignored starting in v5.20) as these are always
    defined starting in that release
o   Compile pattern only once.
a   ASCII-restrict: Use ASCII for \d, \s, \w and [[:posix:]]
    character classes; specifying two a's adds the further
    restriction that no ASCII character will match a
    non-ASCII one under /i.
l   Use the current run-time locale's rules.
u   Use Unicode rules.
d   Use Unicode or native charset, as in 5.12 and earlier.
n   Non-capture mode. Don't let () fill in $1, $2, etc...

Если предварительно скомпилированный шаблон вставлен в более крупный шаблон, то эффект "msixpluadn" будет распространяться соответствующим образом. Эффект модификатора /o не распространяется, будучи ограниченным теми шаблонами, которые его явно используют.

Модификаторы /a, /d, /l, и /u (добавлено в Perl 5.14) управляют правилами набора символов, но /a — единственный, который вы, вероятно, захотите указать явно; остальные три выбираются автоматически различными прагмами.

См. perlre для дополнительной информации о допустимом синтаксисе для STRING и для подробного рассмотрения семантики регулярных выражений. В частности, все модификаторы, за исключением в значительной степени устаревшего /o, подробно описаны в "Modifiers" в perlre. /o описан в следующем разделе.

m/PATTERN/msixpodualngc
/PATTERN/msixpodualngc

Ищет в строке соответствие шаблону и в контексте скаляра возвращает true, если поиск успешен, и false, если неудачен. Если строка не указана с помощью оператора =~ или !~, ищется строка $_. (Указанная с =~ строка не обязательно должна быть lvalue — она может быть результатом вычисления выражения, но помните, что оператор =~ довольно жёстко связывается.) См. также perlre.

Параметры описаны в qr// выше; дополнительно доступны следующие модификаторы процесса поиска соответствия:

g  Match globally, i.e., find all occurrences.
c  Do not reset search position on a failed match when /g is
   in effect.

Если "/" — разделитель, то начальный m необязателен. С помощью m вы можете использовать любую пару символов, не являющихся пробелами (ASCII), в качестве разделителей. Это особенно полезно для поиска соответствия в именах путей, содержащих "/", чтобы избежать LTS (синдрома "наклонённой зубочистки"). Если "?" — разделитель, то применяется правило поиска соответствия только один раз, описанное в m?PATTERN? ниже. Если "'" (одинарная кавычка) — разделитель, интерполяция переменных в PATTERN не выполняется. При использовании разделителя, являющегося допустимым символом в идентификаторе, требуется пробел после m.

PATTERN может содержать переменные, которые будут интерполироваться каждый раз, когда будет оцениваться поиск соответствия, за исключением случаев, когда разделитель — одинарная кавычка. (Обратите внимание, что $(, $), и $| не интерполируются, потому что они похожи на тесты на конец строки.) Perl не будет повторно компилировать шаблон, если какая-либо интерполированная переменная, содержащаяся в нём, не изменится. Вы можете принудительно заставить Perl пропустить тест и никогда не перекомпилировать, добавив /o (что означает "один раз") после конечного разделителя. В старые времена Perl ненужно перекомпилировал регулярные выражения, и этот модификатор был полезен, чтобы сказать ему этого не делать ради скорости. Но теперь, единственные причины использовать /o — одна из следующих:

  1. Переменные имеют длину в тысячи символов, и вы знаете, что они не изменяются, и вам нужно выжать последнюю каплю скорости, заставив Perl пропустить проверку этого. (Существует плата за обслуживание за это, так как упоминание /o означает обещание, что вы не будете изменять переменные в шаблоне. Если вы их измените, Perl этого даже не заметит.)

  2. вы хотите, чтобы шаблон использовал начальные значения переменных независимо от того, изменяются они или нет. (Но существуют более разумные способы достижения этого, чем использование /o.)

  3. Если шаблон содержит встроенный код, такой как

    use re 'eval';
    $code = 'foo(?{ $x })';
    /$code/

    то perl будет перекомпилировать каждый раз, даже если строка шаблона не изменилась, чтобы убедиться, что текущее значение $x видно каждый раз. Используйте /o , если хотите избежать этого.

В конечном счёте, использование /o практически никогда не является хорошей идеей.

Пустой шаблон //

Если PATTERN вычисляется в пустую строку, используется последнее успешно сопоставленное регулярное выражение вместо него. В этом случае учитываются только флаги g и c в пустом шаблоне; другие флаги берутся из исходного шаблона. Если ранее не было успешного соответствия, это будет (беззвучно) действовать как настоящий пустой шаблон (который всегда будет соответствовать).

Обратите внимание, что возможно ввести Perl в заблуждение, заставив его считать // (пустой regex) на самом деле // (оператор "определено или"). Perl обычно довольно хорошо справляется с этим, но в некоторых патологических случаях это может сработать, например $x/// (это ($x) / (//) или $x // /?) и print $fh // (print $fh(// или print($fh //?). Во всех этих примерах Perl будет предполагать, что вы имели в виду оператор "определено или". Если вы имели в виду пустой regex, просто используйте скобки или пробелы для разбора неоднозначности или даже добавьте префикс m в пустой regex (так // становится m//).

Сопоставление в контексте списка

Если параметр /g не используется, m// в контексте списка возвращает список, состоящий из подвыражений, сопоставленных скобками в шаблоне, то есть ($1, $2, $3...) (Обратите внимание, что здесь $1 и т. д. также заданы). При отсутствии скобок в шаблоне возвращаемое значение — список (1) при успехе. С или без скобок, при неудаче возвращается пустой список.

Примеры:

open(TTY, "+</dev/tty")
   || die "can't access /dev/tty: $!";

<TTY> =~ /^y/i && foo();       # do foo if desired

if (/Version: *([0-9.]*)/) { $version = $1; }

next if m#^/usr/spool/uucp#;

# poor man's grep
$arg = shift;
while (<>) {
   print if /$arg/o; # compile only once (no longer needed!)
}

if (($F1, $F2, $Etc) = ($foo =~ /^(\S+)\s+(\S+)\s*(.*)/))

Этот последний пример разделяет $foo на первые два слова и остальную часть строки, и присваивает эти три поля $F1, $F2, и $Etc. Условие истинно, если каким-либо переменным были присвоены значения; то есть, если шаблон сопоставлен.

Модификатор /g указывает на глобальный поиск соответствия шаблона — то есть поиск как можно большего количества совпадений в строке. Как он ведёт себя, зависит от контекста. В контексте списка он возвращает список подстрок, сопоставленных любыми захватывающими скобками в регулярном выражении. Если скобок нет, он возвращает список всех совпадающих строк, как если бы вокруг всего шаблона были скобки.

В скалярном контексте каждое выполнение m//g находит следующее соответствие, возвращая true, если оно соответствует, и false, если больше нет соответствий. Позицию после последнего совпадения можно читать или устанавливать с помощью функции pos(); см. "pos" в perlfunc. Неудачное соответствие обычно сбрасывает позицию поиска в начало строки, но вы можете избежать этого, добавив модификатор /c (например, m//gc). Изменение целевой строки также сбрасывает позицию поиска.

\G assertion

Вы можете смешивать соответствия m//g с m/\G.../g, где \G — утверждение нулевой ширины, которое соответствует точно той позиции, где предыдущее m//g, если таковое было, остановилось. Без модификатора /g, утверждение \G всё равно закрепляется на pos() так, как оно было в начале операции (см. "pos" в perlfunc), но поиск соответствия, естественно, выполняется только один раз. Использование \G без /g на целевой строке, к которой ранее не применялся поиск соответствия m//g, эквивалентно использованию утверждения \A для поиска соответствия в начале строки. Обратите также внимание, что в настоящее время \G должным образом поддерживается только при закреплении в самом начале шаблона.

Примеры:

# list context
($one,$five,$fifteen) = (`uptime` =~ /(\d+\.\d+)/g);

# scalar context
local $/ = "";
while ($paragraph = <>) {
    while ($paragraph =~ /\p{Ll}['")]*[.!?]+['")]*\s/g) {
        $sentences++;
    }
}
say $sentences;

Вот ещё один способ проверки предложений в абзаце:

my $sentence_rx = qr{
   (?: (?<= ^ ) | (?<= \s ) )  # after start-of-string or
                               # whitespace
   \p{Lu}                      # capital letter
   .*?                         # a bunch of anything
   (?<= \S )                   # that ends in non-
                               # whitespace
   (?<! \b [DMS]r  )           # but isn't a common abbr.
   (?<! \b Mrs )
   (?<! \b Sra )
   (?<! \b St  )
   [.?!]                       # followed by a sentence
                               # ender
   (?= $ | \s )                # in front of end-of-string
                               # or whitespace
}sx;
local $/ = "";
while (my $paragraph = <>) {
   say "NEW PARAGRAPH";
   my $count = 0;
   while ($paragraph =~ /($sentence_rx)/g) {
       printf "\tgot sentence %d: <%s>\n", ++$count, $1;
   }
}

Вот как использовать m//gc с \G:

$_ = "ppooqppqq";
while ($i++ < 2) {
    print "1: '";
    print $1 while /(o)/gc; print "', pos=", pos, "\n";
    print "2: '";
    print $1 if /\G(q)/gc;  print "', pos=", pos, "\n";
    print "3: '";
    print $1 while /(p)/gc; print "', pos=", pos, "\n";
}
print "Final: '$1', pos=",pos,"\n" if /\G(.)/;

Последний пример должен вывести:

1: 'oo', pos=4
2: 'q', pos=5
3: 'pp', pos=7
1: '', pos=7
2: 'q', pos=8
3: '', pos=8
Final: 'q', pos=8

Обратите внимание, что последнее соответствие совпало с q, а не с p, что сделало бы соответствие без якоря \G. Также обратите внимание, что последнее соответствие не обновило pos. pos обновляется только при совпадении /g. Если последнее соответствие действительно совпало с p, значит, вы используете старую (до 5.6.0) версию Perl.

Полезный идиоматический конструкт для сканеров типа lex — /\G.../gc. Вы можете комбинировать несколько таких регулярных выражений для обработки строки по частям, выполняя разные действия в зависимости от того, какое регулярное выражение совпало. Каждое регулярное выражение пытается найти соответствие в позиции, в которой предыдущее остановилось.

$_ = <<'EOL';
   $url = URI::URL->new( "http://example.com/" );
   die if $url eq "xXx";
EOL

LOOP: {
    print(" digits"),       redo LOOP if /\G\d+\b[,.;]?\s*/gc;
    print(" lowercase"),    redo LOOP
                                   if /\G\p{Ll}+\b[,.;]?\s*/gc;
    print(" UPPERCASE"),    redo LOOP
                                   if /\G\p{Lu}+\b[,.;]?\s*/gc;
    print(" Capitalized"),  redo LOOP
                             if /\G\p{Lu}\p{Ll}+\b[,.;]?\s*/gc;
    print(" MiXeD"),        redo LOOP if /\G\pL+\b[,.;]?\s*/gc;
    print(" alphanumeric"), redo LOOP
                           if /\G[\p{Alpha}\pN]+\b[,.;]?\s*/gc;
    print(" line-noise"),   redo LOOP if /\G\W+/gc;
    print ". That's all!\n";
}

Вот вывод (разделен на несколько строк):

line-noise lowercase line-noise UPPERCASE line-noise UPPERCASE
line-noise lowercase line-noise lowercase line-noise lowercase
lowercase line-noise lowercase lowercase line-noise lowercase
lowercase line-noise MiXeD line-noise. That's all!
m?PATTERN?msixpodualngc

Это похоже на поиск m/PATTERN/, но соответствует только один раз между вызовами оператора reset(). Это полезная оптимизация, когда вы хотите увидеть только первое вхождение чего-либо в каждом файле набора файлов, например. Только m?? шаблоны, локальные для текущего пакета, сбрасываются.

while (<>) {
    if (m?^$?) {
                        # blank line between header and body
    }
} continue {
    reset if eof;       # clear m?? status for next file
}

Другой пример переключил первое кодирование "latin1", которое он находит, на "utf8" в файле pod:

s//utf8/ if m? ^ =encoding \h+ \K latin1 ?x;

Поведение совпадения один раз контролируется разделителем совпадения ?; с любым другим разделителем это обычный оператор m//.

В прошлом ведущий m в m?PATTERN? был необязательным, но его отсутствие вызывало предупреждение об устаревании. Начиная с версии 5.22.0, его отсутствие приводит к синтаксической ошибке. Если вы встретите эту конструкцию в более старом коде, вы можете просто добавить m.

s/PATTERN/REPLACEMENT/msixpodualngcer

Ищет в строке шаблон и, если он найден, заменяет этот шаблон текстом замены и возвращает количество произведенных замещений. В противном случае возвращает false (значение, которое является как пустой строкой (""), так и числовым нулем (0) как описано в "Операторы сравнения").

Если используется опция /r (неразрушающая), она выполняет замену на копии строки и вместо возвращения количества замещений возвращает копию, произошла ли замена или нет. Исходная строка никогда не изменяется при использовании /r. Копия всегда будет обычной строкой, даже если вход является объектом или привязанной переменной.

Если строка не указана с помощью оператора =~ или !~, выполняется поиск и изменение переменной $_. Если не используется опция /r, указанная строка должна быть скалярной переменной, элементом массива, элементом хеша или присвоением одному из них; то есть некоторый скалярный lvalue.

Если выбранный разделитель — одиночная кавычка, интерполяция переменных не выполняется ни для PATTERN, ни для REPLACEMENT. В противном случае, если PATTERN содержит $, похожий на переменную, а не на проверку конца строки, переменная будет интерполирована в шаблон во время выполнения. Если вы хотите, чтобы шаблон компилировался только один раз в первый раз, когда переменная интерполируется, используйте опцию /o. Если шаблон вычисляется как пустая строка, вместо этого используется последний успешно выполненный регулярный выражение. См. perlre для получения дополнительной информации об этом.

Опции аналогичны m// с добавлением следующих опций, специфичных для замены:

e   Evaluate the right side as an expression.
ee  Evaluate the right side as a string then eval the
    result.
r   Return substitution and leave the original string
    untouched.

Любой разделитель, не являющийся пробелом, может заменить слеши. Добавьте пробел после s при использовании символа, разрешенного в идентификаторах. Если используются одинарные кавычки, интерпретация строки замены не выполняется (модификатор /e переопределяет это, однако). Обратите внимание, что Perl обрабатывает обратные кавычки как обычные разделители; текст замены не оценивается как команда. Если PATTERN ограничен скобочными кавычками, REPLACEMENT имеет свою пару кавычек, которые могут быть или не быть скобочными кавычками, например, s(foo)(bar) или s<foo>/bar/. /e заставит часть замены обрабатываться как полноценное выражение Perl и оцениваться прямо там и тогда. Однако, проверка синтаксиса выполняется во время компиляции. Вторая модификатор e заставит часть замены eval перед выполнением как выражения Perl.

Примеры:

s/\bgreen\b/mauve/g;              # don't change wintergreen

$path =~ s|/usr/bin|/usr/local/bin|;

s/Login: $foo/Login: $bar/; # run-time pattern

($foo = $bar) =~ s/this/that/;      # copy first, then
                                    # change
($foo = "$bar") =~ s/this/that/;    # convert to string,
                                    # copy, then change
$foo = $bar =~ s/this/that/r;       # Same as above using /r
$foo = $bar =~ s/this/that/r
            =~ s/that/the other/r;  # Chained substitutes
                                    # using /r
@foo = map { s/this/that/r } @bar   # /r is very useful in
                                    # maps

$count = ($paragraph =~ s/Mister\b/Mr./g);  # get change-cnt

$_ = 'abc123xyz';
s/\d+/$&*2/e;               # yields 'abc246xyz'
s/\d+/sprintf("%5d",$&)/e;  # yields 'abc  246xyz'
s/\w/$& x 2/eg;             # yields 'aabbcc  224466xxyyzz'

s/%(.)/$percent{$1}/g;      # change percent escapes; no /e
s/%(.)/$percent{$1} || $&/ge;       # expr now, so /e
s/^=(\w+)/pod($1)/ge;       # use function call

$_ = 'abc123xyz';
$x = s/abc/def/r;           # $x is 'def123xyz' and
                            # $_ remains 'abc123xyz'.

# expand variables in $_, but dynamics only, using
# symbolic dereferencing
s/\$(\w+)/${$1}/g;

# Add one to the value of any numbers in the string
s/(\d+)/1 + $1/eg;

# Titlecase words in the last 30 characters only
substr($str, -30) =~ s/\b(\p{Alpha}+)\b/\u\L$1/g;

# This will expand any embedded scalar variable
# (including lexicals) in $_ : First $1 is interpolated
# to the variable name, and then evaluated
s/(\$\w+)/$1/eeg;

# Delete (most) C comments.
$program =~ s {
    /\*     # Match the opening delimiter.
    .*?     # Match a minimal number of characters.
    \*/     # Match the closing delimiter.
} []gsx;

s/^\s*(.*?)\s*$/$1/;        # trim whitespace in $_,
                            # expensively

for ($variable) {           # trim whitespace in $variable,
                            # cheap
    s/^\s+//;
    s/\s+$//;
}

s/([^ ]*) *([^ ]*)/$2 $1/;  # reverse 1st two fields

$foo !~ s/A/a/g;    # Lowercase all A's in $foo; return
                    # 0 if any were found and changed;
                    # otherwise return 1

Обратите внимание на использование $ вместо \ в последнем примере. В отличие от sed, мы используем форму \<цифра> только в левой части. В любом другом месте это $<цифра>.

Иногда вы не можете просто использовать /g, чтобы получить все изменения, которые вы хотите. Вот два распространенных случая:

# put commas in the right places in an integer
1 while s/(\d)(\d\d\d)(?!\d)/$1,$2/g;

# expand tabs to 8-column spacing
1 while s/\t+/' ' x (length($&)*8 - length($`)%8)/e;

Хотя s/// принимает флаг /c, он не оказывает никакого влияния, кроме вывода предупреждения, если включены предупреждения.

Операторы, подобные кавычкам

q/STRING/
'STRING'

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

$foo = q!I said, "You said, 'She said it.'"!;
$bar = q('This is it.');
$baz = '\n';                # a two-character string
qq/STRING/
"STRING"

Интерполированная строка с двойными кавычками.

$_ .= qq
 (*** The previous line contains the naughty word "$1".\n)
            if /\b(tcl|java|python)\b/i;      # :-)
$baz = "\n";                # a one-character string
qx/STRING/
`STRING`

Строка, которая (возможно) интерполируется и затем выполняется как системная команда через /bin/sh или его эквивалент, если это необходимо. Будут учтены оболочные маски, трубы и перенаправления. Аналогично system, если строка не содержит оболочных метасимволов, она будет выполнена непосредственно. Возвращается собранный стандартный вывод команды; стандартная ошибка не затрагивается. В скалярном контексте она возвращается как одна (возможно, многострочная) строка или undef если оболочка (или команда) не могла быть запущена. В списочном контексте возвращает список строк (как вы определили строки с $/ или $INPUT_RECORD_SEPARATOR), или пустой список, если оболочка (или команда) не могла быть запущена.

Поскольку обратные кавычки не влияют на стандартную ошибку, используйте синтаксис оболочных дескрипторов файлов (при условии, что оболочка поддерживает это), если вам нужно обратиться к этому. Для захвата стандартной ошибки и стандартного вывода команды вместе:

$output = `cmd 2>&1`;

Для захвата стандартного вывода команды, но игнорирования её стандартной ошибки:

$output = `cmd 2>/dev/null`;

Для захвата стандартной ошибки команды, но игнорирования её стандартного вывода (порядок важен здесь):

$output = `cmd 2>&1 1>/dev/null`;

Для обмена стандартным выводом и стандартной ошибкой команды, чтобы захватить стандартную ошибку, но оставить стандартный вывод для выхода через старый стандартный вывод:

$output = `cmd 3>&1 1>&2 2>&3 3>&-`;

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

system("program args 1>program.stdout 2>program.stderr");

Дескриптор файла STDIN, используемый командой, наследуется от STDIN Perl. Например:

open(SPLAT, "stuff")   || die "can't open stuff: $!";
open(STDIN, "<&SPLAT") || die "can't dupe SPLAT: $!";
print STDOUT `sort`;

отобразит отсортированное содержимое файла с именем "stuff".

Использование одинарной кавычки в качестве разделителя защищает команду от интерполяции Perl с двойными кавычками, передавая её вместо этого оболочке:

$perl_info  = qx(ps $$);            # that's Perl's $$
$shell_info = qx'ps $$';            # that's the new shell's $$

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

На некоторых платформах (в частности, подобных DOS), оболочка может не иметь возможности работать с многострочными командами, поэтому размещение новых строк в строке может не дать вам желаемого результата. Возможно, вы сможете оценить несколько команд в одной строке, разделив их символом разделителя команд, если ваша оболочка поддерживает это (например, ; во многих оболочках Unix и & в оболочке Windows NT cmd).

Perl попытается очистить все открытые для вывода файлы перед запуском дочернего процесса, но это может не поддерживаться на некоторых платформах (см. perlport). Для безопасности вам может потребоваться установить $| ($AUTOFLUSH в English) или вызвать метод autoflush() объекта IO::Handle для всех открытых дескрипторов.

Будьте осторожны, так как некоторые оболочки команд могут накладывать ограничения на длину командной строки. Вы должны убедиться, что ваши строки не превышают это ограничение после всех необходимых интерполяций. См. примечания к выпуску, специфичные для платформы, для получения дополнительной информации о вашей конкретной среде.

Использование этого оператора может привести к программам, которые сложно портировать, потому что вызываемые командные строки различаются на разных системах и могут вообще отсутствовать. Например, команда type в оболочке POSIX сильно отличается от команды type в DOS. Это не означает, что следует избегать обратных кавычек, когда они являются правильным способом сделать что-то. Perl был создан как язык склейки, и одна из вещей, которые он склеивает, — это команды. Просто поймите, во что вы ввязываетесь.

Как и system, обратные кавычки помещают код завершения дочернего процесса в $?. Если вы хотите вручную проверить ошибки, вы можете проверить все возможные режимы ошибок, проверив $? следующим образом:

if ($? == -1) {
    print "failed to execute: $!\n";
}
elsif ($? & 127) {
    printf "child died with signal %d, %s coredump\n",
        ($? & 127),  ($? & 128) ? 'with' : 'without';
}
else {
    printf "child exited with value %d\n", $? >> 8;
}

Используйте прагму open, чтобы управлять слоями ввода-вывода при чтении вывода команды, например:

use open IN => ":encoding(UTF-8)";
my $x = `cmd-producing-utf-8`;

qx// также можно вызывать как функцию с "readpipe" в perlfunc.

См. "Операторы ввода-вывода" для получения дополнительной информации.

qw/STRING/

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

split(" ", q/STRING/);

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

qw(foo bar baz)

семантически эквивалентно списку:

"foo", "bar", "baz"

Некоторые часто встречающиеся примеры:

use POSIX qw( setlocale localeconv )
@EXPORT = qw( foo bar baz );

Распространенная ошибка — попытка разделения слов запятыми или введение комментариев в многострочную строку qw. По этой причине прагма use warnings и переключатель -w (то есть, переменная $^W) выводит предупреждения, если STRING содержит символ "," или "#".

tr/SEARCHLIST/REPLACEMENTLIST/cdsr
y/SEARCHLIST/REPLACEMENTLIST/cdsr

Транслитерирует все вхождения символов, найденных (или не найденных, если указан модификатор /c) в списке поиска, на соответствующий по позиции символ в списке замены, возможно удаляя некоторые, в зависимости от указанных модификаторов. Возвращает количество заменённых или удалённых символов. Если строка не указана с помощью оператора =~ или !~, то транслитерируется строка $_.

Для поклонников sed, y предоставляется в качестве синонима для tr.

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

Если не используется опция /r, строка, указанная с помощью =~, должна быть скалярной переменной, элементом массива, элементом хэша или присваиванием одному из них; другими словами, lvalue.

Если символы, разделяющие SEARCHLIST и REPLACEMENTLIST, это одинарные кавычки (tr'SEARCHLIST'REPLACEMENTLIST'), единственная интерполяция — удаление \ из пар \\.

В противном случае, диапазон символов может быть указан дефисом, поэтому tr/A-J/0-9/ выполняет ту же замену, что и tr/ACEGIBDFHJ/0246813579/.

Если SEARCHLIST ограничен скобочными кавычками, REPLACEMENTLIST должен иметь свою пару кавычек, которые могут быть или не быть скобочными кавычками; например, tr[aeiouy][yuoiea] или tr(+\-*/)/ABCD/.

Символы могут быть литералами или (если разделители не одинарные кавычки) любыми из последовательностей escape, принимаемых в строках с двойными кавычками. Но никогда не происходит интерполяция переменных, поэтому "$" и "@" всегда обрабатываются как литералы. Дефис в начале или конце, или предшествующий обратной косой чертой, также всегда рассматривается как литерал. Подробности о последовательностях escape находятся в таблице в начале этого раздела.

Обратите внимание, что tr не выполняет классы символов регулярных выражений, такие как \d или \pL. Оператор tr не эквивалентен утилите tr(1). tr[a-z][A-Z] преобразует 26 букв от «a» до «z» в верхний регистр, но для изменения регистра, не ограниченного ASCII, используйте lc, uc, lcfirst, ucfirst (все они описаны в perlfunc) или оператор подстановки s/PATTERN/REPLACEMENT/ (с \U, \u, \L, и \l escape-последовательностями интерполяции строк в части REPLACEMENT).

Большинство диапазонов не переносимы между наборами символов, но некоторые из них сигнализируют Perl о выполнении специальной обработки, чтобы сделать их переносимыми. Есть два класса переносимых диапазонов. Первый — любые подмножества диапазонов A-Z, a-z, и 0-9, когда они выражены в виде литералов.

tr/h-k/H-K/

приводит буквы "h", "i", "j", и "k" в верхний регистр и ничего более, независимо от того, какой набор символов использует платформа. В противоположность этому, все

tr/\x68-\x6B/\x48-\x4B/
tr/h-\x6B/H-\x4B/
tr/\x68-k/\x48-K/

выполняют те же капитализации, что и в предыдущем примере, при запуске на платформах ASCII, но что-то совершенно другое на EBCDIC платформах.

Второй класс переносимых диапазонов вызывается, когда одна или обе конечные точки диапазона выражены как \N{...}

$string =~ tr/\N{U+20}-\N{U+7E}//d;

удаляет из $string все символы платформы, эквивалентные любому из Unicode U+0020, U+0021, ... U+007D, U+007E. Это переносимый диапазон, и он имеет одинаковый эффект на каждой платформе. В этом примере это печатаемые символы ASCII. Итак, после выполнения этой операции, $string содержит только управляющие символы и символы, не имеющие эквивалентов в ASCII.

Однако, даже для переносимых диапазонов, не всегда очевидно, что включено, без необходимости обращения к документации. Хороший принцип — использовать только диапазоны, которые начинаются и заканчиваются либо буквами ASCII в одинаковом регистре (b-e, B-E), либо цифрами (1-4). Всё остальное неясно (и непереносимо, если не используется \N{...}). В случае сомнений, укажите наборы символов полностью.

Опции:

c   Complement the SEARCHLIST.
d   Delete found but unreplaced characters.
r   Return the modified string and leave the original string
    untouched.
s   Squash duplicate replaced characters.

Если указан модификатор /d, любые символы, указанные в SEARCHLIST, но не найденные в REPLACEMENTLIST, удаляются. (Обратите внимание, что это немного гибче, чем поведение некоторых программ tr, которые удаляют всё, что они находят в SEARCHLIST, без исключений.)

Если указан модификатор /s, последовательности символов, все расположенные подряд, которые были транслитерированы в один и тот же символ, сжимаются до одного экземпляра этого символа.

my $a = "aaaba"
$a =~ tr/a/a/s     # $a now is "aba"

Если используется модификатор /d, REPLACEMENTLIST всегда интерпретируется точно так, как указано. В противном случае, если REPLACEMENTLIST короче SEARCHLIST, последний символ, если таковой есть, дублируется до тех пор, пока он не станет достаточно длинным. Не будет конечного символа только в том случае, если REPLACEMENTLIST пустой, в этом случае REPLACEMENTLIST копируется из SEARCHLIST. Пустой REPLACEMENTLIST полезен для подсчёта символов в классе или для сжатия последовательностей символов в классе.

tr/abcd//            tr/abcd/abcd/
tr/abcd/AB/          tr/abcd/ABBB/
tr/abcd//d           s/[abcd]//g
tr/abcd/AB/d         (tr/ab/AB/ + s/[cd]//g)  - but run together

Если указан модификатор /c, символы для транслитерации — те, которые НЕ находятся в SEARCHLIST, то есть происходит дополнение. Если /d и/или /s также указаны, они применяются к дополненному SEARCHLIST. Вспомним, что если REPLACEMENTLIST пустой (за исключением случая /d), то вместо него используется копия SEARCHLIST. Эта копия создается после дополнения в соответствии с /c. SEARCHLIST сортируется по порядку кодов символов после дополнения, и любой REPLACEMENTLIST применяется к этому отсортированному результату. Это означает, что в соответствии с /c, порядок символов, указанных в SEARCHLIST, не имеет значения. Это может привести к различным результатам на системах EBCDIC, если REPLACEMENTLIST содержит более одного символа, поэтому в общем случае не рекомендуется использовать /c с таким REPLACEMENTLIST.

Другой способ описания операции таков: Если указан /c, SEARCHLIST сортируется по порядку кодов символов, затем дополняется. Если REPLACEMENTLIST пустой и /d не указан, REPLACEMENTLIST заменяется копией SEARCHLIST (изменённой в соответствии с /c), и эти потенциально изменённые списки используются как основа для последующих действий. Любой символ в целевой строке, который не находится в SEARCHLIST, передаётся без изменений. Каждый другой символ в целевой строке заменяется символом из REPLACEMENTLIST, который по позиции соответствует его партнёру в SEARCHLIST, за исключением того, что в соответствии с /s, второй и последующие символы удаляются в последовательности символов подряд, которые все переводятся в один и тот же символ. Если SEARCHLIST длиннее REPLACEMENTLIST, символы в целевой строке, которые совпадают с символом в SEARCHLIST, для которого нет соответствия в REPLACEMENTLIST, либо удаляются из целевой строки, если указан /d; или заменяются последним символом в REPLACEMENTLIST, если /d не указан.

Примеры:

$ARGV[1] =~ tr/A-Z/a-z/;   # canonicalize to lower case ASCII

$cnt = tr/*/*/;            # count the stars in $_
$cnt = tr/*//;             # same thing

$cnt = $sky =~ tr/*/*/;    # count the stars in $sky
$cnt = $sky =~ tr/*//;     # same thing

$cnt = $sky =~ tr/*//c;    # count all the non-stars in $sky
$cnt = $sky =~ tr/*/*/c;   # same, but transliterate each non-star
                           # into a star, leaving the already-stars
                           # alone.  Afterwards, everything in $sky
                           # is a star.

$cnt = tr/0-9//;           # count the ASCII digits in $_

tr/a-zA-Z//s;              # bookkeeper -> bokeper
tr/o/o/s;                  # bookkeeper -> bokkeeper
tr/oe/oe/s;                # bookkeeper -> bokkeper
tr/oe//s;                  # bookkeeper -> bokkeper
tr/oe/o/s;                 # bookkeeper -> bokkopor

($HOST = $host) =~ tr/a-z/A-Z/;
 $HOST = $host  =~ tr/a-z/A-Z/r; # same thing

$HOST = $host =~ tr/a-z/A-Z/r   # chained with s///r
              =~ s/:/ -p/r;

tr/a-zA-Z/ /cs;                 # change non-alphas to single space

@stripped = map tr/a-zA-Z/ /csr, @original;
                                # /r with map

tr [\200-\377]
   [\000-\177];                 # wickedly delete 8th bit

$foo !~ tr/A/a/    # transliterate all the A's in $foo to 'a',
                   # return 0 if any were found and changed.
                   # Otherwise return 1

Если для одного символа задано несколько транслитераций, используется только первая:

tr/AAA/XYZ/

будет транслитерировать любой символ A в X.

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

eval "tr/$oldlist/$newlist/";
die $@ if $@;

eval "tr/$oldlist/$newlist/, 1" or die $@;
<<EOF

Строчный вид цитирования основан на синтаксисе оболочки «here-document». После << вы указываете строку для завершения цитируемого материала, и все строки, следующие за текущей строкой до строки завершения, являются значением элемента.

Представление строки завершения с ~ указывает, что вы хотите использовать "Вложенные here-документы" (см. ниже).

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

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

Двойные кавычки

Двойные кавычки указывают, что текст будет интерполирован с использованием точно таких же правил, как и обычные двойные кавычки.

   print <<EOF;
The price is $Price.
EOF

   print << "EOF"; # same as above
The price is $Price.
EOF
Одинарные кавычки

Одинарные кавычки указывают, что текст должен обрабатываться буквально без интерполяции его содержимого. Это аналогично одиночным цитируемым строкам, за исключением того, что обратные слэши не имеют специального значения, где \\ обрабатывается как два обратных слэша, а не как один, как в других конструкциях цитирования.

Как и в оболочке, обратный слэш, за которым следует идентификатор без пробелов после << , означает то же, что и строка с одинарными кавычками:

    $cost = <<'VISTA';  # hasta la ...
That'll be $10 please, ma'am.
VISTA

    $cost = <<\VISTA;   # Same thing!
That'll be $10 please, ma'am.
VISTA

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

Обратные кавычки

Содержимое here-документа обрабатывается так же, как если бы строка была вставлена в обратные кавычки. Таким образом, содержимое интерполируется так, как если бы оно было в двойных кавычках, а затем выполняется через оболочку, а результаты выполнения возвращаются.

   print << `EOC`; # execute command and get results
echo hi there
EOC
Вложенные here-документы

Модификатор here-документа ~ позволяет вкладывать ваши here-документы для повышения читаемости кода:

if ($some_var) {
  print <<~EOF;
    This is a here-doc
    EOF
}

Это будет выведено...

This is a here-doc

...без начальных пробелов.

Разделитель используется для определения точного пробела, который необходимо удалить из начала каждой строки. Все строки должны иметь по крайней мере одинаковые начальные пробелы (кроме строк, содержащих только новую строку), иначе perl выдаст ошибку. Табуляции и пробелы могут быть смешаны, но точно соответствуют друг другу. Одна табуляция не равна 8 пробелам!

Дополнительные начальные пробелы (помимо тех, что предшествовали разделителю) сохраняются:

print <<~EOF;
  This text is not indented
    This text is indented with two spaces
            This text is indented with two tabs
  EOF

Наконец, модификатор может быть использован со всеми вышеупомянутыми формами:

<<~\EOF;
<<~'EOF'
<<~"EOF"
<<~`EOF`

И пробелы могут быть использованы между ~ и цитируемыми разделителями:

<<~ 'EOF'; # ... "EOF", `EOF`

Возможна последовательность нескольких here-документов подряд:

   print <<"foo", <<"bar"; # you can stack them
I said foo.
foo
I said bar.
bar

   myfunc(<< "THIS", 23, <<'THAT');
Here's a line
or two.
THIS
and here's another.
THAT

Просто не забудьте поставить точку с запятой в конце, чтобы завершить оператор, так как Perl не знает, что вы не собираетесь этого сделать:

   print <<ABC
179231
ABC
   + 20;

Если вы хотите удалить разделитель строки из своих here-документов, используйте chomp().

chomp($string = <<'END');
This is a string.
END

Если вы хотите, чтобы ваши here-документы были вложены в остальной код, используйте конструкцию <<~FOO , описанную в разделе "Вложенные here-документы":

$quote = <<~'FINIS';
   The Road goes ever on and on,
   down from the door where it began.
   FINIS

Если вы используете here-документ внутри ограниченной конструкции, например, в s///eg, цитируемый материал все равно должен находиться в строке, следующей за маркером <<FOO, что означает, что он может находиться внутри ограниченной конструкции:

s/this/<<E . 'that'
the other
E
 . 'more '/eg;

Это работает так с Perl 5.18. Исторически это было несовместимо, и вам нужно было писать

s/this/<<E . 'that'
 . 'more '/eg;
the other
E

вне оценок строк.

Кроме того, правила цитирования для идентификатора конца строки не связаны с правилами цитирования Perl. q(), qq(), и т.п. не поддерживаются вместо '' и "", и единственная интерполяция — это обратный слэш цитируемого символа:

print << "abc\"def";
testing...
abc"def

Наконец, цитируемые строки не могут занимать несколько строк. Общее правило состоит в том, что идентификатор должен быть строковой литеральной.

Детали парсинга цитируемых конструкций

При столкновении с чем-либо, имеющим несколько различных толкований, Perl использует принцип DWIM (это «Сделай то, что я имею в виду»), чтобы выбрать наиболее вероятное толкование. Эта стратегия настолько успешна, что программисты Perl часто не подозревают о неоднозначности того, что они пишут. Но время от времени представления Perl существенно отличаются от того, что автор честно имел в виду.

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

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

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

Поиск конца

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

Если конструкция — here-документ, конечный разделитель — это строка, содержащая строку завершения в качестве содержимого. Таким образом, <<EOF завершается EOF сразу после "\n" и начиная с первого столбца строки завершения. При поиске строки завершения here-документа ничего не пропускается. Другими словами, строки после синтаксиса here-документа сравниваются со строкой завершения строка за строкой.

Для конструкций, кроме here-документов, используются отдельные символы в качестве начального и конечного разделителей. Если начальный разделитель — открывающая скобка (то есть (, [, {, или <), конечный разделитель — соответствующая закрывающая скобка (то есть ), ], }, или >). Если начальный разделитель — непарный символ, например, / или закрывающая скобка, конечный разделитель такой же, как начальный разделитель. Таким образом, / завершает конструкцию qq//, в то время как ] завершает как qq[], так и qq]] конструкции.

При поиске разделителей одиночных символов экранированные разделители и \\ пропускаются. Например, при поиске завершающего /, сочетания \\ и \/ пропускаются. Если разделители являются скобками, также пропускаются вложенные пары. Например, при поиске закрывающей скобки ], парной с открывающей [, сочетания \\, \], и \[ все пропускаются, а вложенные [ и ] также пропускаются. Однако, когда обратные слэши используются в качестве разделителей (например, qq\\ и tr\\\), ничего не пропускается. Во время поиска конца обратные слэши, экранирующие разделители или другие обратные слэши, удаляются (точнее, они не копируются в безопасное место).

Для конструкций с разделителями из трёх частей (s///, y///, и tr///), поиск повторяется ещё раз. Если первый разделитель не является открывающей скобкой, три разделителя должны быть одинаковыми, например, s!!! и tr))), в этом случае второй разделитель завершает левую часть и сразу же начинает правую часть. Если левая часть ограничена скобками (то есть (), [], {}, или <>), правой части требуется ещё пара разделителей, например s(){} и tr[]//. В этих случаях между двумя частями допускаются пробелы и комментарии, хотя комментарий должен следовать хотя бы за одним пробелом; в противном случае символ, ожидаемый как начало комментария, может рассматриваться как начальный разделитель правой части.

При этом поиске не уделяется внимания семантике конструкции. Таким образом:

"$hash{"$foo/$bar"}"

или:

m/
  bar       # NOT a comment, this slash / terminated m//!
 /x

не образуют законных цитируемых выражений. Цитируемая часть заканчивается на первом " и /, а остальное оказывается синтаксической ошибкой. Поскольку слэш, завершивший m//, последовал за SPACE, пример выше не является m//x, а скорее m// без модификатора /x. Таким образом, встроенный # интерпретируется как литеральный #.

Также во время этого поиска не уделяется внимания \c\ (синтаксис многосимвольного управляющего символа). Таким образом, второй \ в qq/\c\/ интерпретируется как часть \/, и следующий / не распознаётся как разделитель. Вместо этого используйте \034 или \x1c в конце цитируемых конструкций.

Интерполяция

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

<<'EOF'

Интерполяция не выполняется. Обратите внимание, что комбинация \\ остается неизменной, так как экранированные разделители недоступны для here-доков.

m'', шаблон s'''

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

'', q//, tr''', y''', замена s'''

Единственная интерполяция — удаление \ из пар \\. Поэтому "-" в tr''' и y''' обрабатывается буквально как дефис, и диапазон символов недоступен. \1 в замене s''' не работает как $1.

tr///, y///

Интерполяция переменных не происходит. Комбинации для изменения строк по регистру и цитированию, такие как \Q, \U, и \E не распознаются. Другие последовательности экранирования, такие как \200 и \t и символы с обратным слешем, такие как \\ и \- преобразуются в соответствующие литералы. Символ "-" обрабатывается специально, поэтому \- обрабатывается как литеральный "-".

"", ``, qq//, qx//, <file*glob>, <<"EOF"

\Q, \U, \u, \L, \l, \F (возможно, сопоставленные с \E ) преобразуются в соответствующие конструкции Perl. Таким образом, "$foo\Qbaz$bar" преобразуется в $foo . (quotemeta("baz" . $bar)) во внутреннем представлении. Другие последовательности экранирования, такие как \200 и \t и символы с обратным слешем, такие как \\ и \- заменяются соответствующими расширениями.

Следует подчеркнуть, что все, что находится между \Q и \E интерполируется обычным способом. Например, что-то вроде "\Q\\E" не имеет \E внутри. Вместо этого оно имеет \Q, \\, и E, поэтому результат такой же, как и для "\\\\E".

В общем случае, обратные слеши между \Q и \E могут привести к неинтуитивным результатам. Так, "\Q\t\E" преобразуется в quotemeta("\t"), что эквивалентно "\\\t" (так как TAB не является буквенно-цифровым символом). Также обратите внимание на:

$str = '\t';
return "\Q$str";

что может быть ближе к предполагаемому намерению автора "\Q\t\E".

Интерполированные скаляры и массивы преобразуются во внутреннем представлении в операции конкатенации join и "." . Таким образом, "$foo XXX '@arr'" становится:

$foo . " XXX '" . (join $", @arr) . "'";

Все вышеперечисленные операции выполняются одновременно, слева направо.

Поскольку результат "\Q STRING \E" имеет все метасимволы цитированными, нет способа вставить буквальный $ или @ внутри пары \Q\E. Если защищено \, $ будет цитированно как "\\\$"; в противном случае он интерпретируется как начало интерполированного скаляра.

Также обратите внимание, что код интерполяции должен принять решение о том, где заканчивается интерполированный скаляр. Например, означает ли "a $x -> {c}":

"a " . $x . " -> {c}";

или:

"a " . $x -> {c};

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

замена s///

Обработка \Q, \U, \u, \L, \l, \F и интерполяция происходят так же, как и с конструкциями qq//.

На этом шаге \1 неохотно преобразуется в $1 в тексте замены s///, чтобы исправить неисправимых пользователей sed, которые ещё не усвоили более разумный синтаксис. Выводится предупреждение, если директива use warnings или командная строка -w (то есть переменная $^W) были установлены.

RE в m?RE?, /RE/, m/RE/, s/RE/foo/,

Обработка \Q, \U, \u, \L, \l, \F, \E и интерполяция происходят (почти) так же, как и с конструкциями qq//.

Здесь также выполняется обработка \N{...}, и она компилируется в промежуточную форму для компилятора регулярных выражений. (Это потому, что, как упоминалось ниже, компиляция регулярных выражений может выполняться во время выполнения, и \N{...} — это конструкция времени компиляции.)

Однако все другие комбинации \, за которыми следует символ, не подставляются, а только пропускаются, чтобы разобрать их как регулярные выражения на следующем шаге. Поскольку \c пропущено на этом шаге, @ в \c@ в RE возможно обрабатывается как символ массива (например, @foo), хотя тот же текст в qq// дает интерполяцию \c@.

Блоки кода, такие как (?{BLOCK}), обрабатываются временно переданным управлением обратно парсеру Perl, аналогично тому, как интерполированный индекс массива, например "foo$array[1+f("[xyz")]bar", бы обрабатывался.

Кроме того, внутри (?{BLOCK}), (?# comment ), и комментарий # в /x регулярном выражении, обработка не выполняется совсем. Это первый шаг, на котором присутствие модификатора /x имеет значение.

Интерполяция в шаблонах имеет несколько особенностей: $|, $(, $), @+ и @- не интерполируются, а конструкции $var[SOMETHING] оцениваются (несколькими разными оценщиками) либо как элемент массива, либо как $var, за которым следует альтернатива RE. Здесь пригождается обозначение ${arr[$bar]}: /${arr[0-9]}/ интерпретируется как элемент массива -9, а не как регулярное выражение из переменной $arr, за которым следует цифра, что было бы интерпретацией /$arr[0-9]/.

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

Отсутствие обработки \\ создаёт специфические ограничения на послеобработанный текст. Если разделитель /, невозможно получить комбинацию \/ в результате этого шага. / завершит регулярное выражение, \/ будет удалено до / на предыдущем шаге, а \\/ останется неизменным.

Так как / эквивалентно \/ внутри регулярного выражения, это не имеет значения, если разделитель является специальным символом для движка RE, например, в s*foo*bar*, m[foo], или m?foo?; или буквенно-цифровым символом, как в:

m m ^ a \s* b mmx;

В вышеприведенном регулярном выражении, намеренно замаскированном для иллюстрации, разделителем является m, модификатором — mx, а после удаления разделителя регулярное выражение то же, что и для m/ ^ a \s* b /mx. Есть более одной причины, по которой рекомендуется использовать в качестве разделителей не буквенно-цифровые и не пробельные символы.

Этот шаг — последний для всех конструкций, кроме регулярных выражений, которые обрабатываются дальше.

разбор регулярных выражений

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

Всё, что происходит в движке RE, можно лучше обсудить в perlre, но ради последовательности, мы сделаем это здесь.

Это ещё один шаг, где присутствие модификатора /x актуально. Движок RE сканирует строку слева направо и преобразует её в конечный автомат.

Символы с обратным слэшем либо заменяются соответствующими строками символов (как с \{), либо генерируют специальные узлы в конечном автомате (как с \b). Символы, специальные для движка RE (такие как |), генерируют соответствующие узлы или группы узлов. (?#...) комментарии игнорируются. Всё остальное либо преобразуется в строковые литералы для сопоставления, либо игнорируется (как пробелы и комментарии в стиле #, если /x присутствует).

Разбор конструкции именованного класса символов, [...], отличается от правила, используемого для остальной части шаблона. Терминатор этой конструкции находится с помощью тех же правил, что и для поиска терминатора {}-разделённой конструкции, единственное исключение — ], идущий непосредственно за [, обрабатывается так, как будто ему предшествует обратный слэш.

Терминатор выполнения (?{...}) находится путём временного переключения управления на синтаксический анализатор Perl, который должен остановиться в точке, где найден логически соответствующий терминатор }.

Можно просмотреть как строку, переданную движку RE, так и результирующий конечный автомат. Смотрите аргументы debug/debugcolor в use re псевдониме, а также командную строку Perl -Dr, документированную в "Command Switches" в perlrun.

Оптимизация регулярных выражений

Этот шаг указан только для полноты. Поскольку он не меняет семантику, детали этого шага не документированы и могут быть изменены без предварительного уведомления. Этот шаг выполняется над конечным автоматом, сгенерированным на предыдущем этапе.

Именно на этом этапе split() молча оптимизирует /^/ до /^/m.

Операторы Ввода/Вывода

Вам следует знать несколько операторов ввода/вывода.

Строка, заключенная в обратные кавычки (гравированные знаки), сначала подвергается интерполяции двойных кавычек. Затем она интерпретируется как внешняя команда, а результат этой команды — значение строки в обратных кавычках, как в оболочке. В скалярном контексте возвращается одна строка, состоящая из всего вывода. В контексте списка возвращается список значений, по одному на каждую строку вывода. (Вы можете установить $/ для использования другого разделителя строк.) Команда выполняется каждый раз, когда псевдолитерал оценивается. Значение состояния команды возвращается в $? (см. perlvar для интерпретации $?). В отличие от csh, никаких преобразований не выполняется над данными возврата — новые строки остаются новыми строками. В отличие от любой из оболочек, одинарные кавычки не скрывают имена переменных в команде от интерпретации. Чтобы передать буквальный символ доллара в оболочку, вам нужно скрыть его с помощью обратного слэша. Обобщенная форма обратных кавычек — qx//, или вы можете вызвать функцию "readpipe" в perlfunc. (Поскольку обратные кавычки всегда проходят расширение оболочки, см. perlsec для вопросов безопасности.)

В скалярном контексте, оценивание файлового дескриптора в угловых скобках приводит к следующей строке из этого файла (включая перевод строки, если таковой есть), или undef в конце файла или при ошибке. Когда $/ установлено в undef (иногда называемый режимом файла-загрузки) и файл пуст, он возвращает '' первый раз, а затем undef в дальнейшем.

Обычно вам нужно присвоить возвращаемое значение переменной, но есть одна ситуация, где происходит автоматическое присвоение. Если и только если символ ввода — единственное, что находится внутри условного оператора while (даже если он замаскирован как цикл for(;;)), значение автоматически присваивается глобальной переменной $_, уничтожая то, что было там раньше. (Это может показаться странным, но вы будете использовать эту конструкцию практически в каждом вашем скрипте Perl.) Переменная $_ не неявно локализована. Вам придётся поставить local $_; перед циклом, если вы хотите, чтобы это произошло. Более того, если символ ввода или явное присвоение символа ввода скалярной переменной используется в качестве while/for условия, то условие фактически проверяет определённость значения выражения, а не его обычное истинностное значение.

Таким образом, следующие строки эквивалентны:

while (defined($_ = <STDIN>)) { print; }
while ($_ = <STDIN>) { print; }
while (<STDIN>) { print; }
for (;<STDIN>;) { print; }
print while defined($_ = <STDIN>);
print while ($_ = <STDIN>);
print while <STDIN>;

Это также аналогично ведет себя, но присваивает лексической переменной, а не $_:

while (my $line = <STDIN>) { print $line }

В этих циклических конструкциях присвоенное значение (будь то автоматическое или явное присваивание) проверяется на предмет определения. Проверка на определение избегает проблем, когда строка имеет строковое значение, которое рассматривалось бы Perl как ложь; например, "" или "0" без заключительного перевода строки. Если вы действительно хотите, чтобы такие значения завершали цикл, их следует проверить явно:

while (($_ = <STDIN>) ne '0') { ... }
while (<STDIN>) { last unless $_; ... }

В других контекстах boolean, <FILEHANDLE> без явной defined проверки или сравнения вызывает предупреждение, если псевдоним use warnings или командная строка -w (переменная $^W) активны.

Файловые дескрипторы STDIN, STDOUT и STDERR определены заранее. (Файловые дескрипторы stdin, stdout, и stderr также будут работать, за исключением пакетов, где они были бы интерпретированы как локальные идентификаторы, а не глобальные.) Дополнительные файловые дескрипторы могут быть созданы с помощью функции open(), среди других. См. perlopentut и "open" в perlfunc для получения подробностей об этом.

Если <FILEHANDLE> используется в контексте, ожидающем список, возвращается список, содержащий все строки ввода, по одной строке на элемент списка. Легко перейти к довольно большому пространству данных таким образом, поэтому используйте с осторожностью.

<FILEHANDLE> также может быть написано как readline(*FILEHANDLE). См. "readline" в perlfunc.

Пустой файловый дескриптор <> специальный: его можно использовать для эмуляции поведения sed и awk, и любого другого фильтра Unix, принимающего список имён файлов, выполняя то же самое с каждой строкой ввода из всех файлов. Ввод из <> поступает либо со стандартного ввода, либо из каждого файла, указанного в командной строке. Вот как это работает: при первой оценке <>, массив @ARGV проверяется, и если он пуст, $ARGV[0] устанавливается на "-", который при открытии даёт вам стандартный ввод. Затем массив @ARGV обрабатывается как список имён файлов. Цикл

while (<>) {
    ...                     # code for each line
}

эквивалентен следующему псевдокоду Perl:

unshift(@ARGV, '-') unless @ARGV;
while ($ARGV = shift) {
    open(ARGV, $ARGV);
    while (<ARGV>) {
        ...         # code for each line
    }
}

за исключением того, что это не так громоздко сказать и на самом деле сработает. Он действительно перемещает массив @ARGV и помещает текущее имя файла в переменную $ARGV. Он также использует файловый дескриптор ARGV внутри. <> — просто синоним <ARGV>, который является магическим. (Псевдокод выше не работает, потому что он обрабатывает <ARGV> как не магический.)

Поскольку пустой файловый дескриптор использует двухаргументную форму "open" в perlfunc, он интерпретирует специальные символы, поэтому, если у вас есть скрипт такой:

while (<>) {
    print;
}

и вы вызываете его со perl dangerous.pl 'rm -rfv *|', он фактически открывает канал, выполняет команду rm и читает вывод rm из этого канала. Если вы хотите, чтобы все элементы @ARGV интерпретировались как имена файлов, вы можете использовать модуль ARGV::readonly из CPAN или использовать двойные квадратные скобки:

while (<<>>) {
    print;
}

Использование двойных угловых скобок внутри цикла while заставляет open использовать трёхаргументную форму (со вторым аргументом <), поэтому все аргументы в ARGV обрабатываются как буквальные имена файлов (включая "-"). (Обратите внимание, что для удобства, если вы используете <<>> и если @ARGV пуст, он всё равно будет читать со стандартного ввода.)

Вы можете изменять @ARGV до первого <> , пока массив не содержит список имен файлов, который вам нужен. Номера строк ($.) продолжаются так, как будто ввод — один большой счастливый файл. См. пример в "eof" в perlfunc для того, как перезапустить номера строк в каждом файле.

Если вы хотите установить @ARGV в свой собственный список файлов, вперёд. Это устанавливает @ARGV на все текстовые файлы, если @ARGV не было задано:

@ARGV = grep { -f && -T } glob('*') unless @ARGV;

Вы даже можете установить их на команды конвейера. Например, это автоматически фильтрует сжатые аргументы через gzip:

@ARGV = map { /\.(gz|Z)$/ ? "gzip -dc < $_ |" : $_ } @ARGV;

Если вы хотите передать параметры в свой скрипт, вы можете использовать один из модулей Getopts или поставить цикл впереди, как это:

while ($_ = $ARGV[0], /^-/) {
    shift;
    last if /^--$/;
    if (/^-D(.*)/) { $debug = $1 }
    if (/^-v/)     { $verbose++  }
    # ...           # other switches
}

while (<>) {
    # ...           # code for each line
}

Символ <> вернёт undef только для конца файла. Если вы вызовете его снова после этого, он предположит, что вы обрабатываете другой список @ARGV, и если вы не установили @ARGV, он будет читать ввод со стандартного ввода.

Если то, что содержится в угловых скобках, — это простая скалярная переменная (например, $foo), то эта переменная содержит имя файлового дескриптора для ввода, его типглоб или ссылку на то же самое. Например:

$fh = \*STDIN;
$line = <$fh>;

Если то, что находится внутри угловых скобок, не является файловым дескриптором или простой скалярной переменной, содержащей имя файлового дескриптора, типглоб или ссылку на типглоб, оно интерпретируется как шаблон имени файла для использования glob, и возвращается либо список имен файлов, либо следующее имя файла в списке, в зависимости от контекста. Это различие определяется только синтаксическими причинами. Это означает, что <$x> всегда является readline() от косвенного дескриптора, но <$hash{key}> всегда является glob(). Это потому, что $x — это простая скалярная переменная, но $hash{key} — нет — это элемент хэша. Даже <$x > (обратите внимание на дополнительный пробел) обрабатывается как glob("$x "), а не как readline($x).

Сначала выполняется один уровень интерпретации двойных кавычек, но вы не можете сказать <$foo>, потому что это косвенный файловый дескриптор, как объяснено в предыдущем абзаце. (В более старых версиях Perl программисты вставляли фигурные скобки для принудительной интерпретации как glob имен файлов: <${foo}>. В наши дни считается более чистым напрямую вызывать внутреннюю функцию, как glob($foo), что, вероятно, является правильным способом сделать это с самого начала.) Например:

while (<*.c>) {
    chmod 0644, $_;
}

приблизительно эквивалентно:

open(FOO, "echo *.c | tr -s ' \t\r\f' '\\012\\012\\012\\012'|");
while (<FOO>) {
    chomp;
    chmod 0644, $_;
}

за исключением того, что glob фактически выполняется внутренне с использованием стандартного File::Glob расширения. Конечно, самый короткий способ сделать это:

chmod 0644, <*.c>;

Glob (файла) оценивает свой (встроенный) аргумент только при запуске нового списка. Все значения должны быть прочитаны, прежде чем он начнётся заново. В контексте списка это не имеет значения, потому что вы получаете их все в любом случае. Однако в скалярном контексте оператор возвращает следующее значение каждый раз, когда вызывается, или undef при исчерпании списка. Как и при чтении из файлового дескриптора, автоматическое defined генерируется, когда glob появляется в части проверки while, потому что законные возвращаемые значения glob (например, файл под названием 0) в противном случае привели бы к завершению цикла. Опять же, undef возвращается только один раз. Поэтому, если вы ожидаете единственное значение от glob, гораздо лучше сказать

($file) = <blurch*>;

чем

$file = <blurch*>;

потому что последнее будет чередоваться между возвращением имени файла и возвращением ложного значения.

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

@files = glob("$dir/*.[ch]");
@files = glob($files[$i]);

Если выражение glob на основе угловых скобок используется в качестве условия цикла while или for, оно неявным образом присваивается $_. Если используется выражение glob или явное присвоение выражения glob скаляру в качестве условия while/for, то условие фактически проверяет определённость значения выражения, а не его обычное истинное значение.

Свертка констант

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

  'Now is the time for all'
. "\n"
.  'good men to come to.'

и всё это сводится к одной строке во внутренней части. Точно так же, если вы скажете

foreach $file (@filenames) {
    if (-s $file > 5 + 100 * 2**16) {  }
}

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

Нет операций

В Perl официально нет оператора no-op, но голые константы 0 и 1 обрабатываются особым образом, чтобы не генерировать предупреждение в пустом контексте, поэтому, например, вы можете безопасно сделать

1 while foo();

Битовые операторы строк

Битовые строки любого размера могут быть обработаны битовыми операторами (~ | & ^).

Если операнды битового двоичного оператора являются строками разной длины, операторы | и ^ ведут себя так, как будто у более короткого операнда были дополнительные нулевые биты справа, в то время как оператор & ведет себя так, как будто более длинный операнд был усечён до длины более короткого. Разрешение для такого расширения или усечения составляет один или несколько байтов.

# ASCII-based examples
print "j p \n" ^ " a h";            # prints "JAPH\n"
print "JA" | "  ph\n";              # prints "japh\n"
print "japh\nJunk" & '_____';       # prints "JAPH\n";
print 'p N$' ^ " E<H\n";            # prints "Perl\n";

Если вы намерены работать с битовыми строками, убедитесь, что вы предоставляете битовые строки: если операнд — число, это подразумевает числовую битовую операцию. Вы можете явно указать, какой тип операции вы намерены выполнить, используя "" или 0+, как показано в примерах ниже.

$foo =  150  |  105;        # yields 255  (0x96 | 0x69 is 0xFF)
$foo = '150' |  105;        # yields 255
$foo =  150  | '105';       # yields 255
$foo = '150' | '105';       # yields string '155' (under ASCII)

$baz = 0+$foo & 0+$bar;     # both ops explicitly numeric
$biz = "$foo" ^ "$bar";     # both ops explicitly stringy

Это несколько непредсказуемое поведение можно избежать с помощью функции «bitwise», новой в Perl 5.22. Вы можете включить её через use feature 'bitwise' или use v5.28. До Perl 5.28 она обычно выдавала предупреждение в категории "experimental::bitwise". При этой функции четыре стандартных битовых оператора (~ | & ^) всегда являются числовыми. Добавление точки после каждого оператора (~. |. &. ^.) заставляет его обрабатывать операнды как строки:

use feature "bitwise";
$foo =  150  |  105;        # yields 255  (0x96 | 0x69 is 0xFF)
$foo = '150' |  105;        # yields 255
$foo =  150  | '105';       # yields 255
$foo = '150' | '105';       # yields 255
$foo =  150  |. 105;        # yields string '155'
$foo = '150' |. 105;        # yields string '155'
$foo =  150  |.'105';       # yields string '155'
$foo = '150' |.'105';       # yields string '155'

$baz = $foo &  $bar;        # both operands numeric
$biz = $foo ^. $bar;        # both operands stringy

Операторы присваивания этих операторов (&= |= ^= &.= |.= ^.=) ведут себя аналогично при этой функции.

Это фатальная ошибка, если операнд содержит символ, значение кода которого выше 0xFF, и поэтому он не может быть представлен, кроме как в UTF-8. Операция выполняется на копии без UTF-8 для других операндов, закодированных в UTF-8. См. "Семантика байтов и символов" в perlunicode.

См. "vec" в perlfunc для получения информации о манипулировании отдельными битами в битовом векторе.

Целочисленная арифметика

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

use integer;

вы можете сообщить компилятору использовать целочисленные операции (см. integer для подробного объяснения) отсюда до конца окружающего блока. Вложенный блок может отменить это, сказав

no integer;

что действует до конца этого блока. Обратите внимание, что это не означает, что всё является целым числом, а лишь то, что Perl будет использовать целочисленные операции для арифметических, сравнительных и битовых операторов. Например, даже при use integer, если вы возьмёте sqrt(2), вы всё равно получите 1.4142135623731 или около того.

При использовании с числами битовые операторы (& | ^ ~ << >>) всегда производят целочисленные результаты. (Но см. также "Битовые операторы строк".) Однако use integer всё равно имеет смысл для них. По умолчанию их результаты интерпретируются как беззнаковые целые числа, но если use integer активна, их результаты интерпретируются как знаковые целые числа. Например, ~0 обычно вычисляется до большого целочисленного значения. Однако use integer; ~0 является -1 на машинах с дополнением до двух.

Арифметика с плавающей точкой

Хотя use integer предоставляет только целочисленную арифметику, нет аналогичного механизма для автоматического округления или усечения до определённого числа десятичных знаков. Для округления до определённого числа знаков обычно проще использовать sprintf() или printf(). См. perlfaq4.

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

printf "%.20g\n", 123456789123456789;
#        produces 123456789123456784

Проверка на точное равенство или неравенство чисел с плавающей точкой — не лучшая идея. Вот обходной путь (относительно дорогостоящий) для сравнения двух чисел с плавающей точкой на равенство до определённого количества десятичных знаков. См. Кнута, том II, для более надёжного рассмотрения этой темы.

sub fp_equal {
    my ($X, $Y, $POINTS) = @_;
    my ($tX, $tY);
    $tX = sprintf("%.${POINTS}g", $X);
    $tY = sprintf("%.${POINTS}g", $Y);
    return $tX eq $tY;
}

Модуль POSIX (входит в стандартную поставку Perl) реализует ceil(), floor(), и другие математические и тригонометрические функции. Модуль Math::Complex (входит в стандартную поставку Perl) определяет математические функции, которые работают как с действительными, так и с мнимыми числами. Math::Complex не так эффективен, как POSIX, но POSIX не может работать с комплексными числами.

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

Большие числа

Стандартные модули Math::BigInt, Math::BigRat, и Math::BigFloat вместе с пragmaми bignum, bigint, и bigrat обеспечивают арифметику с переменной точностью и перегруженные операторы, хотя сейчас они довольно медленные. В обмен на некоторое увеличение занимаемой памяти и существенное замедление они избегают обычных проблем, связанных с ограниченной точностью представлений.

    use 5.010;
    use bigint;  # easy interface to Math::BigInt
    $x = 123456789123456789;
    say $x * $x;
+15241578780673678515622620750190521

Или с рациональными числами:

use 5.010;
use bigrat;
$x = 3/22;
$y = 4/6;
say "x/y is ", $x/$y;
say "x*y is ", $x*$y;
x/y is 9/44
x*y is 1/11

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

Вот краткий, но неполный обзор:

Math::String           treat string sequences like numbers
Math::FixedPrecision   calculate with a fixed precision
Math::Currency         for currency calculations
Bit::Vector            manipulate bit vectors fast (uses C)
Math::BigIntFast       Bit::Vector wrapper for big numbers
Math::Pari             provides access to the Pari C library
Math::Cephes           uses the external Cephes C library (no
                       big numbers)
Math::Cephes::Fraction fractions via the Cephes library
Math::GMP              another one using an external C library
Math::GMPz             an alternative interface to libgmp's big ints
Math::GMPq             an interface to libgmp's fraction numbers
Math::GMPf             an interface to libgmp's floating point numbers

Выбирайте с умом.

© 1993–2020 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.32.0/perlop

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API