Spec-Zone.ru › Perl 5.28

perlop

СОДЕРЖАНИЕ

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

ИМЯ

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

ОПИСАНИЕ

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

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

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

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

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

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

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

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

Операторы 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    < > <= >= lt gt le ge
nonassoc    == != <=> 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.

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

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

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

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

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

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

# 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 + 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), которая фактически работает с числами с плавающей точкой внутри).

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

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

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

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

Унарный оператор "~" выполняет побитовое отрицание, то есть дополнение до единицы. Например, 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 — "сдвиг по модулю количества битов слова", так что, например,

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

но это совершенно случайно.

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

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

Операторы с именами (унарные)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Бинарная операция "~~" выполняет интеллектуальное сравнение своих аргументов. Интеллектуальное сравнение описано в следующем разделе.

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

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

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

Оператор интеллектуального сравнения

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

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

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

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

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. То есть, каждый элемент интеллектуально сравнивается с элементом с тем же индексом в другом массиве.[3]
3. Если обнаружена циклическая ссылка, то используется ссылка на равенство.
4. Либо фактическое число, либо строка, которая выглядит как число.

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

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

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

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

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

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;

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

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";
}

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

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

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

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.

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

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 является объект, который не перегружает ~~, он вызывает исключение "Smartmatching a non-overloaded object breaks encapsulation". Это связано с тем, что нет необходимости углубляться, чтобы определить, содержит ли объект что-то. Все эти операции запрещены для объектов без перегрузки ~~:

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

Однако, вы можете изменить способ сопоставления объекта с помощью перегрузки оператора ~~. Это позволяет расширить стандартную семантику 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 // связан с его оператором "or" в стиле C. Фактически, он точно такой же, как ||, за исключением того, что он проверяет определённость левой части, а не её истинность. Таким образом, EXPR1 // EXPR2 возвращает значение EXPR1 при условии, что оно определено, в противном случае возвращается значение EXPR2 (EXPR1 оценивается в скалярном контексте, EXPR2 в контексте самого //). Как правило, это тот же результат, что и defined(EXPR1) ? EXPR1 : EXPR2 (за исключением того, что тернарная форма может использоваться как lvalue, в то время как EXPR1 // EXPR2 не может). Это очень полезно для предоставления значений по умолчанию для переменных. Если вы хотите проверить, определено ли хотя бы одно из $x и $y, используйте defined($x // $y).

Операторы ||, // и && возвращают последнее вычисленное значение (в отличие от C's || и &&, которые возвращают 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

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

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

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

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

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

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

чтобы получить даты с ведущими нулями.

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

Начиная с Perl 5.26, оператор диапазона в списковом контексте для строк работает как ожидается в рамках "use feature 'unicode_strings". В предыдущих версиях и за пределами этой функции он демонстрирует "The "Unicode Bug"" in 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} ])+/).

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

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

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

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

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

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

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

Оператор может быть присвоен, если оба вторые и третьи аргументы являются левыми значениями (т. е. им можно присвоить значение):

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

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

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

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

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

Вместо этого:

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

Это следует записать проще как:

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

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

"=" является обычным оператором присваивания.

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

$x += 2;

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

$x = $x + 2;

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

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

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

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

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

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

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

Аналогично,

($x += 2) *= 3;

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

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

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

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

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

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

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

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

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

Например:

use constant FOO => "something";

my %h = ( FOO => 23 );

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

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

Это НЕ:

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

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

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

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

print time.shift => "bbb";

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

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

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

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

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

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

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

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

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

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

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

Логическое И

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

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

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

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

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

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

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

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

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

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

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

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

Вот что имеет C, чего нет в Perl:

унарный &

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

унарный *

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

(TYPE)

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

Операторы кавычек и похожие на них

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

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

    * unless the delimiter is ''.

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

q{foo{bar}baz}

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

'foo{bar}baz'

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

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

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

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

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

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

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

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

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: SMILEY)
\x1b         [2,8]  restricted range hex char (example: ESC)
\N{name}     [3]    named Unicode character or character sequence
\N{U+263D}   [4,8]  Unicode character (example: FIRST QUARTER MOON)
\c[          [5]    control char      (example: chr(27))
\o{23072}    [6,8]  octal char        (example: SMILEY)
\033         [7,8]  restricted range octal char  (example: ESC)
[1]

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

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

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

[2]

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

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

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

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

[4]

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

[5]

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

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

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

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

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

Использование любого другого символа после "c" помимо перечисленных выше не рекомендуется, а с версии Perl 5.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 независимо от родной кодировки. Название символа в 256-й позиции (индексируется с 0) в Unicode — LATIN CAPITAL LETTER A WITH MACRON.

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

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

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

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

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

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

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

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

Все системы используют виртуальный символ "\n" для представления разделителя строк, называемого "новой строкой". Не существует такого понятия, как неизменный физический символ новой строки. Это всего лишь иллюзия, создаваемая операционной системой, драйверами устройств, библиотеками C и Perl. Не все системы читают "\r" как ASCII CR и "\n" как ASCII LF. Например, на старых 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 применяется после интерполяции и обработки escape-последовательностей.

"abc\Qfoo\tbar$s\Exyz"

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

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

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

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

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

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

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

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

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

qr/STRING/msixpodualn

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

Например,

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

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

s/my.STRING/foo/is;

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

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

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

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

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

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

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

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

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

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

m/PATTERN/msixpodualngc
/PATTERN/msixpodualngc

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

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

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

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

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

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

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

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

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

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

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

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

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

Обратите внимание, что Perl можно ввести в заблуждение, заставив его думать, что // (пустое регулярное выражение) фактически является // (оператор «определено или»). 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.

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

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

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

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

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

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

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

Другой пример заменяет первое найденное кодирование "latin1" на "utf8" в файле pod:

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

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

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

s/PATTERN/REPLACEMENT/msixpodualngcer

Ищет в строке шаблон и, если он найден, заменяет этот шаблон на текст замены, возвращая количество произведённых замещений. В противном случае возвращает ложь (значение, которое является как пустой строкой (""), так и числовым нулём (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

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

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

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

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

Операторы типа кавычек

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/
"СТРОКА"

Двойная строка, интерполируемая строка.

$_ .= 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 или его эквивалента. Будут учтены shell-подстановки, конвейеры и перенаправления. Возвращается собранный стандартный вывод команды; стандартная ошибка не затрагивается. В скалярном контексте она возвращается как одна (возможно многострочная) строка или undef в случае неудачи команды. В списочном контексте возвращает список строк (как вы определили строки с помощью $/ или $INPUT_RECORD_SEPARATOR), или пустой список в случае неудачи команды.

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

$output = `cmd 2>&1`;

Чтобы поймать STDOUT команды, но отбросить STDERR:

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

Чтобы поймать STDERR команды, но отбросить STDOUT (порядок важен здесь):

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

Чтобы обменять STDOUT и STDERR команды, чтобы поймать STDERR, но оставить STDOUT на старом STDERR:

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

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

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

Как эта строка оценивается, полностью зависит от интерпретатора команд вашей системы. На большинстве платформ вам нужно будет защитить shell-метасимволы, если вы хотите, чтобы они обрабатывались буквально. На практике это сделать трудно, так как неясно, какие символы экранировать. См. 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`;

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

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

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

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

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

Диапазон символов может быть указан дефисом, поэтому tr/A-J/0-9/ выполняет ту же замену, что и tr/ACEGIBDFHJ/0246813579/. Для поклонников sed, y предоставляется как синоним для tr. Если список SEARCHLIST ограничен скобками, список REPLACEMENTLIST должен иметь свою пару скобок, которые могут быть или не быть скобками; например, tr[aeiouy][yuoiea] или tr(+\-*/)/ABCD/.

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

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

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

tr/h-k/H-K/

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

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

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

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

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

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

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

Опции:

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

Если указан модификатор /c, набор символов SEARCHLIST дополняется. Например, эти два эквивалентны (точное максимальное значение зависит от вашей платформы):

tr/\x00-\xfd/ABCD/c
tr/\xfe-\x{7fffffff}/ABCD/

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

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

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

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

Примеры:

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

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

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

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

tr/a-zA-Z//s;               # bookkeeper -> bokeper

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

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

tr/AAA/XYZ/

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

This is a here-doc

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

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

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

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

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

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

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

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

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

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

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

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

   print <<ABC
179231
ABC
   + 20;

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

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

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

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

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

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

Он работает таким образом начиная с Perl 5.18. Исторически он был несогласованным, и вам пришлось бы написать

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

вне eval строк.

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

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

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

Подробности синтаксического разбора цитируемых конструкций

При столкновении с чем-либо, что может иметь несколько различных толкований, Perl использует принцип DWIM (это «Do What I Mean») для выбора наиболее вероятного толкования. Эта стратегия настолько успешна, что программисты 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'

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

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

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

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

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

tr///, y///

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

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

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

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

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

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

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

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

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

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

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

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

или:

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

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

замена s///

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

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

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

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

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

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

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

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

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

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

m m ^ a \s* b mmx;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

В скалярном контексте, вычисление дескриптора файла в угловых скобках возвращает следующую строку из этого файла (включая, если есть, новую строку), или undef в конце файла или при ошибке. Когда $/ установлено на undef (иногда известный как режим "file-slurp") и файл пуст, он возвращает '' в первый раз, а затем 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 заставляет открытие использовать трёхаргументную форму (где вторым аргументом является <), поэтому все аргументы в 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), эта переменная содержит имя дескриптора файла для ввода, или его типглоб, или ссылку на то же самое. Например:

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

Функция (file)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. См. "Byte and Character Semantics" in perlunicode.

См. "vec" in 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–2020 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.28.3/perlop

Spec-Zone.ru

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