Spec-Zone.ru › Perl 5.30

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 — "сдвиг по модулю wordbits", так что, например,

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Для сравнения, не учитывающего регистр, посмотрите на функцию смены регистра "fc" в perlfunc, доступную в Perl версии 5.16 или более поздней:

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

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

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

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

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

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

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. Либо фактическое число, либо строка, которая выглядит как число.

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

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

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

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

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

use v5.10.1;

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

my @array = qw(red blue green);

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

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

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

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

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". В предыдущих версиях и за пределами этого функционала он демонстрирует "Проблему Юникода" в 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";

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

$x += 2;

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

$x = $x + 2;

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

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

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

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

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

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

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

Аналогично,

($x += 2) *= 3;

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

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

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

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

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

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

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

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

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

Например:

use constant FOO => "something";

my %h = ( FOO => 23 );

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

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

НЕ:

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

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

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

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

print time.shift => "bbb";

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

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

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

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

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

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

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

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

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

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

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

Логическое И

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

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

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

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

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

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

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

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

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

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

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

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

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

унарный &

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

унарный *

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

(TYPE)

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

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

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

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

    * unless the delimiter is ''.

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

q{foo{bar}baz}

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

'foo{bar}baz'

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

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

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

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

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

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

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

Следующие последовательности 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]".

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

Если между фигурными скобками нет допустимых цифр, генерируемый символ — это нулевой символ (\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]

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

[4]

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

[5]

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

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

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

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

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

Использование любых других символов после "c" помимо перечисленных выше не рекомендуется, и начиная с Perl v5.20, единственными фактически разрешёнными символами являются печатные символы ASCII, за исключением открытой фигурной скобки "{". Что происходит для любого из разрешённых других символов, так это то, что значение получается путём побитового XOR с седьмым битом, который равен 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 интерпретирует его как код Юникода, и результатом является соответствующий символ Юникода. Например, \x{50} и \o{120} оба представляют собой число 80 в десятичной системе, которое меньше 256, поэтому число интерпретируется в соответствии с родной кодировкой набора символов. В ASCII символом в 80-й позиции (индексированной с 0) является буква "P", а в EBCDIC — символ амперсанда "&". \x{100} и \o{400} оба равны 256 в десятичной системе, поэтому число интерпретируется как код Юникода независимо от родной кодировки. Имя символа в 256-й позиции (индексированной с 0) в Юникоде — LATIN CAPITAL LETTER A WITH MACRON.

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

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

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

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

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

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

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

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

Все системы используют виртуальный символ "\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.

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

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

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

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

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

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

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

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

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

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

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

s/PATTERN/REPLACEMENT/msixpodualngcer

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

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

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

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

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

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

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

Примеры:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Поскольку обратные кавычки не влияют на стандартную ошибку, используйте синтаксис оболочки для описателя файла (предполагая, что оболочка поддерживает это), если вам нужно учесть это. Для захвата 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 $$

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

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

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

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

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

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

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

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

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

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

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

qw/STRING/

Вычисляется как список слов, извлечённых из СТРОКА, используя встроенные пробелы в качестве разделителей слов. Его можно примерно рассматривать как:

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) выдают предупреждения, если СТРОКА содержит символ "," или "#".

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

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

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

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

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

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

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

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

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

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

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

tr/h-k/H-K/

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

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

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

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

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

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

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

Опции:

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

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

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

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

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

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

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

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

Примеры:

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

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

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

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

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

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

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

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

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

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

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

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

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

tr/AAA/XYZ/

преобразует любой A в X.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

   print << `EOC`; # execute command and get results
echo hi there
EOC
Отступы Here-docs

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

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

Это выведет…

This is a here-doc

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

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

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

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

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

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

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

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

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

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

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

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

   print <<ABC
179231
ABC
   + 20;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Поиск конца

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

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

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

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

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

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

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

или:

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

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

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

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

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

<<'EOF'

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

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

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

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

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

tr///, y///

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

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

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

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

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

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

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

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

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

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

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

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

или:

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

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

замена s///

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

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

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

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

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

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

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

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

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

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

m m ^ a \s* b mmx;

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

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

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

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

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

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

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

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

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

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

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

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

На этом этапе split() беззвучно оптимизирует /^/ до значения /^/m.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

while (<>) {
    print;
}

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

while (<<>>) {
    print;
}

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

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

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

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

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

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

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

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

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

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

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

Например:

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

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

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

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

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

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

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

chmod 0644, <*.c>;

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

($file) = <blurch*>;

чем

$file = <blurch*>;

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

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

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

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

Свёртывание констант

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

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

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

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

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

Пустые операторы

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

1 while foo();

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

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

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

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

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

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

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

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

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

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

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

Это фатальная ошибка, если операнд содержит символ с порядковым значением выше 0xFF, а значит, его нельзя представить, кроме как в UTF-8. Операция выполняется на копии без UTF-8 для других операндов, закодированных в UTF-8. См. "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

Несколько модулей позволяют вам выполнять вычисления с неограниченной или фиксированной точностью (ограниченной только объёмом памяти и временем CPU). Также существуют некоторые нестандартные модули, которые обеспечивают более быструю реализацию через внешние библиотеки 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.30.3/perlop

Spec-Zone.ru

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