Spec-Zone.ru › Perl 5.34

perlop

СОДЕРЖАНИЕ

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

ИМЯ

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 есть общее правило, что операнды оператора вычисляются слева направо. Несколько операторов, таких как &&=, имеют специальные правила вычисления, которые могут привести к тому, что операнд вообще не будет вычисляться; в целом, оператор верхнего уровня в выражении контролирует вычисление операндов.

Некоторые операторы сравнения, в качестве своей ассоциативности, цепочкой связываются с некоторыми операторами того же приоритета (но никогда не с операторами разного приоритета). Эта цепочка означает, что каждое сравнение выполняется на двух аргументах, окружающих его, причём каждый внутренний аргумент участвует в двух сравнениях, а результаты сравнения неявно ANDed. Таким образом, "$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
nonassoc    isa
chained     < > <= >= lt gt le ge
chain/na    == != eq ne <=> cmp ~~
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 перед увеличением (чтобы пост-инкремент значения undef возвращал 0, а не undef).

Оператор автодекремента не обладает магией.

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

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

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

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

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

Унарный оператор "-" выполняет арифметическое отрицание, если операнд является числовым, включая любую строку, похожую на число. Если операндом является идентификатор, возвращается строка, состоящая из знака минус, соединённого с идентификатором. В противном случае, если строка начинается со знака плюс или минус, возвращается строка, начинающаяся с противоположного знака. Следствием этих правил является то, что -bareword эквивалентно строке "-bareword". Однако, если строка начинается с неалфавитногo символа (за исключением "+" или "-" ), Perl попытается преобразовать строку в число, и выполнится арифметическое отрицание. Если строку нельзя корректно преобразовать в число, Perl выдаст предупреждение Аргумент "строка" не является числовым в операции отрицания (-) в....

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

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

Если функция «побитовая» включена с помощью 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 — "сдвиг по модулю wordbits", так что, например,

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, которые возвращают true или false, обычно возвращают значения, которые можно безопасно использовать как числа. Например, операторы сравнения в этом разделе и операторы равенства в следующем возвращают 1 для true и специальную версию пустой строки, "", которая считается нулём, но исключена из предупреждений о неправильных числовых преобразованиях, точно так же, как "0 but true".

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Бинарный оператор "<=>" возвращает -1, 0 или 1, в зависимости от того, является ли левый аргумент численно меньше, равен или больше правого аргумента. Если ваша платформа поддерживает значения "не числа" (NaN) как числовые значения, использование их с "<=>" возвращает undef. NaN не является "<", "==", ">", "<=" или ">=" ничем (даже NaN), поэтому эти 5 операторов возвращают false. NaN != NaN возвращает true, как и 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" используют порядок сортировки (collation), заданный текущим LC_COLLATE локалем, если активна форма use locale, включающая сортировку. См. perllocale. Не используйте их с Unicode, используйте только с кодировками 8-битного локаля legacy. Модули Unicode::Collate и Unicode::Collate::Locale предлагают гораздо более мощные решения для проблем с сортировкой.

Для регистронезависимых сравнений используйте функцию преобразования регистра "fc" в perlfunc, доступную в Perl версии 5.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 рекурсивно сравнивает вложенные массивы, это всё равно сообщит, что "red" находится в массиве.

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, перегрузка может или не может быть вызвана. Для простых строк или чисел "in" становится эквивалентным этому:

$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;

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

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

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

Бинарный оператор "^" возвращает операнды, побитовое исключающее ИЛИ.

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

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

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

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

Логическое И по стилю C

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

Логическое ИЛИ по стилю C

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

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

Хотя у него нет прямого эквивалента в C, оператор Perl // связан с оператором C-стиля "or". На самом деле он точно такой же, как ||, за исключением того, что он проверяет определённость левой части, а не её истинность. Таким образом, 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 );

    Примечание: В версиях Perl 5.30 и ниже *любая* строка в левой части, начинающаяся с "0", включая строку "0" сама по себе, вызовет магическое поведение инкрементирования строк. Это означает, что в этих версиях Perl "0".."-1" будет производить "0" через "99", что несовместимо с 0..-1, которая производит пустой список. Это также означает, что "0".."9" теперь производит список целых чисел, а не список строк.

  • Если начальное значение не является частью магической последовательности инкрементирования (то есть непустая строка, соответствующая /^[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/, следующее вернёт только альфу:

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-й аргументы являются допустимыми lvalue (то есть к ним можно присвоить значение):

($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;

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

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

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

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

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

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

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

Точно так же,

($x += 2) *= 3;

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

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

Аналогично, присваивание списка в контексте списка генерирует список lзначений, которым присваивается значение, а присваивание списка в скалярном контексте возвращает количество элементов, полученное выражением в правой части присваивания.

Три многоточия битовых операторов присваивания (&.= |.= ^.=) являются новыми в 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 (стандартный начиная с v5.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)
\x{ 263A }          Same, but shows optional blanks inside and
                    adjoining the braces
\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)

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

[1]

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

Пробелы (табуляция или пробелы) могут отделять число от фигурных скобок.

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

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

[2]

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

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

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

Результат — символ или последовательность символов Unicode, заданные значением имя. См. 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)

Другими словами, это символ, у которого код точки был побитовым исключающим ИЛИ с 64. \c? — это УДАЛЕНИЕ на платформах ASCII, потому что ord("?") ^ 64 равно 127, а \c@ — это NULL, потому что порядковый номер "@" равен 64, а побитовое исключающее ИЛИ с самим собой даёт 0.

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

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

Использование любого другого символа после "c" помимо перечисленных выше не рекомендуется, и начиная с Perl v5.20, единственными фактически разрешёнными символами являются печатаемые символы ASCII за исключением открывающей фигурной скобки "{". Что происходит с любыми другими разрешёнными символами, так это то, что значение выводится путем побитового исключающего ИЛИ с седьмым битом, который равен 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 независимо от того, какой нативный набор символов.

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

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

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

\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. Например, на старых Mac (до MacOS X) эти символы использовались в обратном порядке, а на системах без символов конца строки вывод "\n" мог не генерировать никаких реальных данных. В общем случае используйте "\n", когда вы имеете в виду "новый символ строки" для вашей системы, но используйте литеральные ASCII-символы, когда вам нужен точный символ. Например, большинство сетевых протоколов ожидают и предпочитают CR+LF ("\015\012" или "\cM\cJ") для символов конца строки, и хотя они часто принимают только "\012", они редко допускают только "\015". Если вы привыкнете использовать "\n" для сетевых операций, вы можете в один прекрасный день столкнуться с проблемами.

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

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

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

"abc\Qfoo\tbar$s\Exyz"

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

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

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

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

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

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

END_OF_DOCUMENT_MARKER

Помимо описанного выше поведения, 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 (leaning toothpick syndrome). Если "?" является разделителем, то применяется правило поиска совпадения только один раз, описанное в 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 с толку, заставив его подумать, что // (пустое регулярное выражение) на самом деле // (оператор определён-или). Perl обычно довольно хорошо справляется с этим, но некоторые патологические случаи могут вызвать это, такие как $x/// (это ($x) / (//) или $x // /?) и print $fh // (print $fh(// или print($fh //?). Во всех этих примерах Perl предположит, что вы имели в виду оператор определён-или. Если вы имели в виду пустое регулярное выражение, просто используйте скобки или пробелы для устранения неоднозначности, или даже префикс пустого регулярного выражения с m (так, // становится 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 на целевой строке, с которой ранее не выполнялось совпадение /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? был необязателен, но его пропуск приводил к предупреждению о устаревании. Начиная с версии v5.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, мы используем форму \<digit> только в левой части. В любом другом месте это $<digit>.

Иногда вам не удается использовать просто /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, строка, указанная с помощью =~, должна быть скалярной переменной, элементом массива, элементом хеша или присвоением одному из них; другими словами, левосторонним значением.

Символы, разделяющие СПИСОК_ПОИСКА и СПИСОК_ЗАМЕНЫ, могут быть любым печатным символом, а не только прямым слэшем. Если это одинарные кавычки (tr'SEARCHLIST'REPLACEMENTLIST'), единственная интерполяция — удаление \ из пар \\.

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

Если СПИСОК_ПОИСКА ограничен заключительными кавычками, СПИСОК_ЗАМЕНЫ должен иметь свою пару кавычек, которые могут быть или не быть заключительными кавычками; например, tr[aeiouy][yuoiea] или tr(+\-*/)/ABCD/.

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

Обратите внимание, что 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 эскейпами интерполяции строк в части ЗАМЕНЫ).

Большинство диапазонов не переносимы между наборами символов, но некоторые сигнализируют 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, любые символы, указанные в СПИСКЕ_ПОИСКА, но отсутствующие в СПИСКЕ_ЗАМЕНЫ, удаляются. (Обратите внимание, что это немного более гибко, чем поведение некоторых программ tr, которые удаляют всё, что они находят в СПИСКЕ_ПОИСКА, независимо от всего остального).

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

my $a = "aaabbbca";
$a =~ tr/ab/dd/s;     # $a now is "dcd"

Если используется модификатор /d, СПИСОК_ЗАМЕНЫ всегда интерпретируется точно как указано. В противном случае, если СПИСОК_ЗАМЕНЫ короче СПИСКА_ПОИСКА, последний символ, если таковой имеется, дублируется до тех пор, пока его длина не станет достаточной. Не будет конечного символа только в том случае, если СПИСОК_ЗАМЕНЫ пустой, в этом случае СПИСОК_ЗАМЕНЫ копируется из СПИСКА_ПОИСКА. Пустой СПИСОК_ЗАМЕНЫ полезен для подсчёта символов в классе или для сжатия последовательностей символов в классе.

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, символы для преобразования — это те, которые НЕ находятся в СПИСКЕ_ПОИСКА, то есть, он дополняется. Если /d и/или /s также указаны, они применяются к дополненному СПИСКЕ_ПОИСКА. Вспомните, что если СПИСОК_ЗАМЕНЫ пустой (кроме случаев /d) он копируется из СПИСКА_ПОИСКА. Эта копия создаётся после дополнения в соответствии с /c. СПИСОК_ПОИСКА сортируется по порядку кодовых точек после дополнения, и любой СПИСОК_ЗАМЕНЫ применяется к этому отсортированному результату. Это означает, что при /c, порядок символов, указанных в СПИСКЕ_ПОИСКА, не имеет значения. Это может привести к различным результатам на системах EBCDIC, если СПИСОК_ЗАМЕНЫ содержит более одного символа, поэтому использование /c с таким СПИСОК_ЗАМЕНЫ обычно не переносимо.

Другой способ описания операции: Если /c указан, СПИСОК_ПОИСКА сортируется по порядку кодовых точек, а затем дополняется. Если СПИСОК_ЗАМЕНЫ пустой и /d не указан, СПИСОК_ЗАМЕНЫ заменяется копией СПИСКА_ПОИСКА (как изменённого согласно /c). Эти потенциально изменённые списки используются в качестве основы для дальнейшего. Любой символ в целевой строке, который не находится в СПИСКЕ_ПОИСКА, передаётся без изменений. Каждый другой символ в целевой строке заменяется символом из СПИСКА_ЗАМЕНЫ, позиционно соответствующим его парному элементу в СПИСКЕ_ПОИСКА, за исключением того, что при /s, второй и последующие символы удаляются в последовательности символов, которые все преобразуются в один и тот же символ. Если СПИСОК_ПОИСКА длиннее СПИСКА_ЗАМЕНЫ, символы в целевой строке, которые соответствуют символу в СПИСКЕ_ПОИСКА, у которого нет соответствия в СПИСКЕ_ЗАМЕНЫ, либо удаляются из целевой строки, если /d указан, или заменяются последним символом в СПИСКЕ_ЗАМЕНЫ, если /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/

преобразует любой символ А в Х.

Поскольку таблица преобразования создаётся на этапе компиляции, ни СПИСОК_ПОИСКА, ни СПИСОК_ЗАМЕНЫ не подвергаются интерполяции двойных кавычек. Это означает, что если вы хотите использовать переменные, вы должны использовать eval():

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

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

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

Префикс ~ перед строкой завершения указывает, что вы хотите использовать «Отступы в документах-источниках» (см. ниже).

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

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

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

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

   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, где нет необходимости беспокоиться об экранировании содержимого, что является полезным для генераторов кода.

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

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

   print << `EOC`; # execute command and get results
echo hi there
EOC
Отступы в документах-источниках

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

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`

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

   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;

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

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

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

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

Если вы используете документ-источник внутри разделительной конструкции, например, в 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 выполняет разное количество проходов, от одного до четырёх, но эти проходы всегда выполняются в одном и том же порядке.

Поиск конца

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

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

Для конструкций, кроме документов-источников, используются отдельные символы в качестве начальных и конечных разделителей. Если начальный разделитель – это открывающая пунктуация (то есть (, [, {, или <), конечный разделитель – это соответствующая закрывающая пунктуация (то есть ), ], }, или >). Если начальный разделитель – это непарный символ, такой как /, или закрывающая пунктуация, конечный разделитель такой же, как и начальный разделитель. Таким образом, / завершает конструкцию 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'

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

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, за которым следует альтернатива регулярного выражения. Вот где пригодится обозначение ${arr[$bar]}: /${arr[0-9]}/ интерпретируется как элемент массива -9, а не как регулярное выражение из переменной $arr, за которым следует цифра, что было бы интерпретацией /$arr[0-9]/. Поскольку голосование между различными оценщиками может происходить, результат непредсказуем.

Отсутствие обработки \\ создает особые ограничения на обработанный текст. Если разделитель /, то комбинацию \/ нельзя получить на этом шаге. / завершит регулярное выражение, \/ будет удалено до / на предыдущем шаге, а \\/ останется как есть. Поскольку / эквивалентно \/ внутри регулярного выражения, это не имеет значения, если разделитель не является специальным символом для движка регулярных выражений, например, в 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" in perlrun.

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

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

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

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

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

Строка, заключённая в обратные кавычки (гравированные знаки), сначала претерпевает интерполяцию двойных кавычек. Затем она интерпретируется как внешняя команда, и вывод этой команды является значением строки в обратных кавычках, как в оболочке. В скалярном контексте возвращается одна строка, состоящая из всего вывода. В списочном контексте возвращается список значений, по одному на каждую строку вывода. (Вы можете установить $/ для использования другого разделителя строк.) Команда выполняется каждый раз, когда псевдолитерал оценивается. Значение состояния команды возвращается в $? (см. perlvar для интерпретации $?). В отличие от csh, никакой перевод не выполняется над возвращаемыми данными - новые строки остаются новыми строками. В отличие от любой из оболочек, одинарные кавычки не скрывают имён переменных в команде от интерпретации. Чтобы передать литеральную запятую в оболочку, необходимо скрыть её с помощью обратного слэша. Обобщённой формой обратных кавычек является qx//, или вы можете вызвать функцию "readpipe" in 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 $_; ... }

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

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

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

<FILEHANDLE> также может быть написано как readline(*FILEHANDLE). См. "readline" in 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" in perlfunc, он интерпретирует специальные символы, поэтому, если у вас есть скрипт такого рода:

while (<>) {
    print;
}

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

while (<<>>) {
    print;
}

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

Вы можете изменить @ARGV перед первым <>, пока массив в итоге содержит список имен файлов, которые вы на самом деле хотите. Номера строк ($.) продолжаются так, как будто вход был одним большим счастливым файлом. См. пример в "eof" in 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), то эта переменная содержит имя файлового дескриптора для ввода, его typeglob или ссылку на тот же самый.

$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 нет официального оператора без действия, но оголённые константы 0 и 1 являются особыми случаями, которые не выдают предупреждение в контексте void, так что, например, вы можете безопасно сделать

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, а также плагины 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–2021 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.34.0/perlop

Spec-Zone.ru

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