perlop
СОДЕРЖАНИЕ
- НАЗВАНИЕ
- ОПИСАНИЕ
- Приоритет и ассоциативность операторов
- Операнды и операторы списков (слева направо)
- Оператор стрелки
- Автоинкремент и автодекремент
- Возведение в степень
- Символьные унарные операторы
- Операторы связывания
- Мультипликативные операторы
- Аддитивные операторы
- Операторы сдвига
- Именованные унарные операторы
- Операторы сравнения
- Операторы равенства
- Оператор экземпляра класса
- Оператор Smartmatch
- Побитовое И
- Побитовое ИЛИ и исключающее ИЛИ
- Логическое И (стиль C)
- Логическое ИЛИ (стиль C)
- Логическое определенное ИЛИ
- Операторы диапазонов
- Условный оператор
- Операторы присваивания
- Оператор запятой
- Операторы списков (справа налево)
- Логическое НЕ
- Логическое И
- Логическое ИЛИ и исключающее ИЛИ
- Операторы C, отсутствующие в Perl
- Операторы кавычек и подобные
- Операторы регулярных выражений, подобные кавычкам
- Операторы, подобные кавычкам
- Подробности разбора скобочных конструкций
- Операторы Ввода/Вывода
- Сворачивание констант
- Пустые операторы
- Побитовые строковые операторы
- Целочисленная арифметика
- Арифметика с плавающей точкой
- Более большие числа
НАЗВАНИЕ
perlop - Операторы и приоритеты Perl
ОПИСАНИЕ
В Perl, оператор определяет выполняемую операцию независимо от типа операндов. Например, $x + $y всегда является числовым сложением, и если $x или $y не содержат чисел, сначала производится попытка их преобразования в числа.
Это отличается от многих других динамических языков, где операция определяется типом первого аргумента. Это также означает, что Perl имеет две версии некоторых операторов, одну для числового и одну для строкового сравнения. Например, $x == $y сравнивает два числа на равенство, а $x eq $y сравнивает две строки.
Однако есть несколько исключений: x может быть либо повторением строк, либо повторением списков, в зависимости от типа левого операнда, а &, |, ^ и ~ могут быть либо строковыми, либо числовыми побитовыми операциями.
Приоритет и ассоциативность операторов
Приоритет и ассоциативность операторов в Perl работают примерно так же, как и в математике.
Приоритет операторов означает, что некоторые операторы объединяют операнды более тесно, чем другие. Например, в 2 + 4 * 5, умножение имеет более высокий приоритет, поэтому 4 * 5 группируется как правый операнд сложения, а не 2 + 4 как левый операнд умножения. Это как если бы выражение было написано 2 + (4 * 5), а не (2 + 4) * 5. Таким образом, выражение даёт 2 + 20 == 22, а не 6 * 5 == 30.
Ассоциативность операторов определяет, что происходит, если используется последовательность одинаковых операторов друг за другом: обычно они группируются слева направо или справа налево. Например, в 9 - 3 - 2, вычитание является левоассоциативным, поэтому 9 - 3 группируется как левый операнд второго вычитания, а не 3 - 2 как правый операнд первого вычитания. Это как если бы выражение было написано (9 - 3) - 2, а не 9 - (3 - 2). Таким образом, выражение даёт 6 - 2 == 4, а не 9 - 1 == 8.
Для простых операторов, которые вычисляют все свои операнды, а затем комбинируют значения каким-либо образом, приоритет и ассоциативность (и скобки) накладывают определённые требования к порядку этих комбинирующих операций. Например, в 2 + 4 * 5, группировка, заданная приоритетом, означает, что умножение 4 и 5 должно выполняться до сложения 2 и 20, просто потому, что результат этого умножения требуется в качестве одного из операндов сложения. Но порядок операций не полностью определяется этим: в 2 * 2 + 4 * 5 оба умножения должны выполняться до сложения, но группировка ничего не говорит о порядке выполнения двух умножений. Фактически Perl имеет общее правило, что операнды оператора вычисляются слева направо. Несколько операторов, таких как &&=, имеют специальные правила вычисления, которые могут привести к тому, что операнд вообще не будет вычислен; в целом, оператор верхнего уровня в выражении контролирует вычисление операндов.
Некоторые операторы сравнения, в зависимости от ассоциативности, цепляются с некоторыми операторами того же приоритета (но никогда с операторами разного приоритета). Это цепляние означает, что каждое сравнение выполняется на двух аргументах, окружающих его, каждый внутренний аргумент участвует в двух сравнениях, а результаты сравнения неявно умножаются по логическому И. Таким образом, "$x < $y <= $z" ведет себя точно так же, как "$x < $y && $y <= $z", предполагая, что "$y" — это простая скалярная переменная. Логическое И выполняет короткое замыкание, как и "&&" , останавливая последовательность сравнений, как только одно из них даст false.
В цепочке сравнений каждый аргумент вычисляется не более одного раза, даже если он участвует в двух сравнениях, но результат вычисления извлекается для каждого сравнения. (Он не вычисляется вообще, если короткое замыкание означает, что он не требуется ни для одного сравнения.) Это имеет значение, если вычисление внутреннего аргумента является дорогостоящим или не детерминированным. Например,
if($x < expensive_sub() <= $z) { ... не совсем как
if($x < expensive_sub() && expensive_sub() <= $z) { ... а скорее как
my $tmp = expensive_sub();
if($x < $tmp && $tmp <= $z) { ... в том, что подпрограмма вызывается только один раз. Однако это не совсем так, как последний код, потому что цепное сравнение на самом деле не включает никаких временных переменных (именованных или иных): нет присваивания. Это не сильно отличается, когда выражение является вызовом обычной подпрограммы, но имеет большее значение при работе с подпрограммой lvalue или если выражение аргумента генерирует какой-то необычный тип скаляра другими способами. Например, если выражение аргумента генерирует связанную скалярную переменную, выражение вычисляется, чтобы получить эту скалярную переменную не более одного раза, но значение этой скалярной переменной может извлекаться до двух раз, один раз для каждого сравнения, в котором она фактически используется.
В этом примере выражение вычисляется только один раз, и связанная скалярная переменная (результат выражения) извлекается для каждого сравнения, которое её использует.
if ($x < $tied_scalar < $z) { ... В следующем примере выражение вычисляется только один раз, и связанная скалярная переменная извлекается один раз как часть операции внутри выражения. Результат этой операции извлекается для каждого сравнения, что обычно не имеет значения, если результат этого выражения не является магическим из-за перегрузки оператора.
if ($x < $tied_scalar + 42 < $z) { ... Некоторые операторы не являются ассоциативными, что означает, что использование последовательности таких операторов одного и того же приоритета является синтаксической ошибкой. Например, "$x .. $y .. $z" — это ошибка.
Операторы Perl имеют следующую ассоциативность и приоритет, перечисленные от наивысшего приоритета к наименьшему. Операторы, заимствованные из C, сохраняют те же отношения приоритета друг с другом, даже там, где приоритет C немного странный. (Это облегчает изучение Perl для тех, кто знаком с C.) За очень немногими исключениями, все они работают только со скалярными значениями, а не с массивами.
left terms and list operators (leftward)
left ->
nonassoc ++ --
right **
right ! ~ ~. \ and unary + and -
left =~ !~
left * / % x
left + - .
left << >>
nonassoc named unary operators
nonassoc isa
chained < > <= >= lt gt le ge
chain/na == != eq ne <=> cmp ~~
left & &.
left | |. ^ ^.
left &&
left || //
nonassoc .. ...
right ?:
right = += -= *= etc. goto last next redo dump
left , =>
nonassoc list operators (rightward)
right not
left and
left or xor В следующих разделах эти операторы рассматриваются подробно в том же порядке, в котором они появляются в таблице выше.
Многие операторы могут быть перегружены для объектов. См. overload.
Операнды и операторы списков (слева направо)
У TERM самый высокий приоритет в Perl. Они включают переменные, операторы кавычек и подобные, любое выражение в скобках и любую функцию, аргументы которой заключены в скобки. На самом деле, в этом смысле нет функций, только операторы списков и унарные операторы, которые ведут себя как функции, потому что вы помещаете аргументы в скобки. Всё это документировано в perlfunc.
Если за оператором списка (print(), и т. д.) или за унарным оператором (chdir(), и т. д.) следует левая скобка как следующий токен, оператор и аргументы в скобках рассматриваются как имеющие самый высокий приоритет, как и обычный вызов функции.
При отсутствии скобок приоритет операторов списков, таких как print, sort, или chmod, очень высок или очень низок в зависимости от того, смотрите ли вы на левую или правую сторону оператора. Например, в
@ary = (1, 3, sort 4, 2);
print @ary; # prints 1324 запятые справа от sort оцениваются перед sort, но запятые слева оцениваются после. Другими словами, операторы списков, как правило, поглощают все аргументы, которые следуют за ними, а затем ведут себя как простое выражение относительно предыдущего выражения. Будьте осторожны со скобками:
# These evaluate exit before doing the print:
print($foo, exit); # Obviously not what you want.
print $foo, exit; # Nor is this.
# These do the print before evaluating exit:
(print $foo), exit; # This is what you want.
print($foo), exit; # Or this.
print ($foo), exit; # Or even this. Также обратите внимание, что
print ($foo & 255) + 1, "\n"; вероятно, не делает того, чего вы ожидаете с первого взгляда. Скобки заключают список аргументов для print, который оценивается (печатается результат $foo & 255). Затем к возвращаемому значению print (обычно 1) добавляется единица. Результат выглядит примерно так:
1 + 1, "\n"; # Obviously not what you meant. Чтобы сделать то, что вы имели в виду должным образом, вы должны написать:
print(($foo & 255) + 1, "\n"); См. "Именованные унарные операторы" для более подробного обсуждения этого.
Также как термины парсятся do {} и eval {} конструкции, а также вызовы подпрограмм и методов, и анонимные конструкторы [] и {}.
См. также "Операторы кавычек и похожие на кавычки" в конце этого раздела, а также "Операторы Ввода/Вывода".
Оператор Стрелки
"->" — это инфиксный оператор разыменования, как и в C и C++. Если правая часть — это [...], {...} или индекс (...), то левая часть должна быть жёсткой или символической ссылкой на массив, хеш или подпрограмму соответственно. (Или, технически говоря, местоположение, способное хранить жёсткую ссылку, если это ссылка на массив или хеш, используемая для присваивания.) См. perlreftut и perlref.
В противном случае, правая часть — имя метода или простая скалярная переменная, содержащая либо имя метода, либо ссылку на подпрограмму, и (если это имя метода) левая часть должна быть либо объектом (благословенной ссылкой), либо именем класса (то есть именем пакета). См. perlobj.
Случаи разыменования (в отличие от случаев вызова метода) несколько расширены функцией postderef. Для получения подробностей об этой функции см. "Синтаксис постфиксного разыменования" в perlref.
Автоинкремент и автодекремент
"++" и "--" работают как в C. То есть, если они расположены перед переменной, они увеличивают или уменьшают переменную на единицу перед возвращением значения, а если после — увеличивают или уменьшают после возвращения значения.
$i = 0; $j = 0;
print $i++; # prints 0
print ++$j; # prints 1 Обратите внимание, что, как и в C, Perl не определяет, когда переменная увеличивается или уменьшается. Вы просто знаете, что это будет сделано до или после возвращения значения. Это также означает, что изменение переменной дважды в одном операторе приведёт к неопределённому поведению. Избегайте операторов вроде:
$i = $i ++;
print ++ $i + $i ++; Perl не гарантирует, каким будет результат вышеуказанных операторов.
Оператор автоинкремента имеет немного дополнительной встроенной магии. Если вы увеличиваете числовую переменную или переменную, которая когда-либо использовалась в числовом контексте, вы получаете обычное увеличение. Однако, если переменная использовалась только в строковых контекстах с момента её установки и имеет значение, отличное от пустой строки и соответствует шаблону /^[a-zA-Z]*[0-9]*\z/, инкремент выполняется как строковый, сохраняя каждый символ в своём диапазоне с переносом:
print ++($foo = "99"); # prints "100"
print ++($foo = "a0"); # prints "a1"
print ++($foo = "Az"); # prints "Ba"
print ++($foo = "zz"); # prints "aaa" undef всегда обрабатывается как числовой, и, в частности, изменяется на 0 перед увеличением (так что пост-инкремент неопределенного значения вернёт 0 вместо undef).
Оператор автодекремента не является магическим.
Возведение в степень
Бинарный оператор "**" — это оператор возведения в степень. Он связывает ещё сильнее, чем унарный минус, поэтому -2**4 — это -(2**4), а не (-2)**4. (Это реализовано с помощью функции C pow(3), которая фактически работает с double внутри).
Обратите внимание, что некоторые выражения возведения в степень не определены: к ним относятся 0**0, 1**Inf и Inf**0. Не ожидайте каких-либо конкретных результатов от этих особых случаев, результаты зависят от платформы.
Символьные унарные операторы
Унарный "!" выполняет логическое отрицание, то есть «не». См. также not для версии с более низким приоритетом.
Унарный "-" выполняет арифметическое отрицание, если операнд числовой, включая любые строки, похожие на числа. Если операнд идентификатор, возвращается строка, состоящая из знака минус, соединённого с идентификатором. В противном случае, если строка начинается с плюса или минуса, возвращается строка, начинающаяся с противоположного знака. Одним из последствий этих правил является то, что -bareword эквивалентно строке "-bareword". Однако, если строка начинается с небуквенного символа (исключая "+" или "-"), Perl попытается преобразовать строку в число, и выполняется арифметическое отрицание. Если строку нельзя чисто преобразовать в число, Perl выдаст предупреждение Аргумент "строка" не является числом в отрицании (-) в ....
Унарный "~" выполняет побитовое отрицание, то есть дополнение до 1. Например, 0666 & ~027 равно 0640. (См. также "Целочисленная арифметика" и "Побитовые строковые операторы".) Обратите внимание, что ширина результата зависит от платформы: ~0 имеет ширину 32 бита на 32-битной платформе, но 64 бита на 64-битной платформе, поэтому, если вы ожидаете определённую ширину бита, помните, что следует использовать оператор "&" для маскировки избыточных битов.
Начиная с Perl 5.28, попытка дополнения строки, содержащей символ с порядковым значением выше 255, является ошибкой.
Если функция «побитовая» включена с помощью use feature 'bitwise' или use v5.28, то унарный "~" всегда обрабатывает свой аргумент как число, а альтернативная форма оператора "~." всегда обрабатывает свой аргумент как строку. Поэтому ~0 и ~"0" оба дадут 2**32-1 на 32-битных платформах, тогда как ~.0 и ~."0" оба дадут "\xff". До Perl 5.28 эта функция выдавала предупреждение в категории "experimental::bitwise".
Унарный "+" не оказывает никакого влияния, даже на строки. Он полезен синтаксически для отделения имени функции от выражения в скобках, которое в противном случае интерпретировалось бы как полный список аргументов функции. (См. примеры выше в разделе "Выражения и операторы списков (влево)".)
Унарный "\" создаёт ссылки. Если его операнд — это единственная вещь с префиксом, он создаёт ссылку на этот объект. Если его операнд — это список в скобках, он создаёт ссылки на вещи, упомянутые в списке. В противном случае он помещает свой операнд в контекст списка и создаёт список ссылок на скаляры в списке, предоставленном операндом. См. perlreftut и perlref. Не путайте это поведение с поведением обратной косой черты внутри строки, хотя обе формы передают понятие защиты следующего элемента от интерполяции.
Операторы связывания
Бинарный "=~" связывает скалярное выражение с соответствием шаблону. Некоторые операции по умолчанию ищут или изменяют строку $_. Этот оператор заставляет такую операцию работать с другой строкой. Правый аргумент — это шаблон поиска, замена или транслитерация. Левый аргумент — то, что должно быть найдено, заменено или транслитерировано вместо стандартного значения $_. При использовании в скалярном контексте возвращаемое значение, как правило, указывает на успех операции. Исключение составляют замена (s///) и транслитерация (y///) с опцией /r (неразрушающей), которые вызывают возвращаемое значение результатом замены. Поведение в контексте списка зависит от конкретного оператора. См. "Операторы, похожие на кавычки с регулярными выражениями" для подробностей и perlretut для примеров использования этих операторов.
Если правый аргумент — это выражение, а не шаблон поиска, замена или транслитерация, он интерпретируется как шаблон поиска во время выполнения. Обратите внимание, что это означает, что его содержимое будет интерполировано дважды, поэтому
'\\' =~ q'\\'; не подходит, так как движок регулярных выражений попытается скомпилировать шаблон \, который он будет считать синтаксической ошибкой.
Бинарный "!~" такой же, как "=~", за исключением того, что возвращаемое значение логически отрицается.
Бинарный "!~" с неразрушающей заменой (s///r) или транслитерацией (y///r) — это синтаксическая ошибка.
Операторы умножения
Бинарный "*" умножает два числа.
Бинарный "/" делит два числа.
Бинарный оператор "%" — это оператор модуля, который вычисляет остаток от деления первого аргумента на второй. Даны целые операнды $m и $n: Если $n положительно, то $m % $n равно $m минус наибольшее кратное $n, меньшее или равное $m. Если $n отрицательно, то $m % $n равно $m минус наименьшее кратное $n, которое не меньше $m (то есть результат будет меньше или равен нулю). Если операнды $m и $n являются числами с плавающей точкой и абсолютное значение $n (то есть abs($n)) меньше (UV_MAX + 1), то в операции будут использованы только целые части $m и $n (Примечание: здесь UV_MAX означает максимальное значение для типа беззнакового целого). Если абсолютное значение правого операнда (abs($n)) больше или равно (UV_MAX + 1), то "%" вычисляет остаток от деления с плавающей точкой $r в уравнении ($r = $m - $i*$n), где $i — определенное целое число, которое делает $r иметь тот же знак, что и правый операнд $n (не левый операнд $m, как в функции C fmod()) и абсолютное значение меньше, чем у $n. Обратите внимание, что когда use integer в силе, "%" даёт прямой доступ к оператору модуля, реализованному вашим компилятором C. Этот оператор не так хорошо определён для отрицательных операндов, но он будет выполняться быстрее.
Бинарный оператор x — это оператор повторения. В скалярном контексте или если левый операнд не заключён в скобки и не является списком qw//, он выполняет повторение строки. В этом случае он обеспечивает скалярный контекст левому операнду и возвращает строку, состоящую из левого операнда, повторённого заданное количество раз правым операндом. Если оператор x находится в контексте списка, а левый операнд заключён в скобки или является списком qw//, он выполняет повторение списка. В этом случае он обеспечивает контекст списка левому операнду и возвращает список, состоящий из левого операнда, повторённого заданное количество раз правым операндом. Если правый операнд равен нулю или отрицателен (с выводом предупреждения при отрицательном значении), он возвращает пустую строку или пустой список, в зависимости от контекста.
print '-' x 80; # print row of dashes
print "\t" x ($tab/8), ' ' x ($tab%8); # tab over
@ones = (1) x 80; # a list of 80 1's
@ones = (5) x @ones; # set all elements to 5 Операторы сложения
Бинарный оператор "+" возвращает сумму двух чисел.
Бинарный оператор "-" возвращает разность двух чисел.
Бинарный оператор "." конкатенирует две строки.
Операторы сдвига
Бинарный оператор "<<" возвращает значение своего левого аргумента, сдвинутого влево на количество бит, указанное правым аргументом. Аргументы должны быть целыми числами. (См. также "Целочисленная арифметика".)
Бинарный оператор ">>" возвращает значение своего левого аргумента, сдвинутого вправо на количество бит, указанное правым аргументом. Аргументы должны быть целыми числами. (См. также "Целочисленная арифметика".)
Если use integer (см. "Целочисленная арифметика") в силе, то используются знакомые целые числа C (арифметический сдвиг), иначе используются беззнаковые целые числа C (логический сдвиг), даже для отрицательных сдвигаемых. В арифметическом сдвиге вправо знаковый бит дублируется слева, в логическом сдвиге слева вставляются нули.
В любом случае, реализация не будет генерировать результаты, превышающие размер типа целого числа, с которым был создан Perl (32 бита или 64 бита).
Сдвиг на отрицательное число бит означает обратный сдвиг: сдвиг влево становится сдвигом вправо, сдвиг вправо становится сдвигом влево. Это отличается от C, где отрицательный сдвиг не определён.
Сдвиг на большее количество бит, чем размер целых чисел, в большинстве случаев приводит к нулю (все биты исчезают), за исключением того, что при use integer правое сдвижение отрицательного сдвигаемого результата в -1. Это отличается от C, где сдвиг на слишком большое количество бит не определён. Общее поведение в C — "сдвиг по модулю разрядности слова", так что, например,
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) Что касается приоритета, операторы проверки файла, такие как -f, -M, и т. д. обрабатываются как именованные унарные операторы, но они не следуют этому функциональному правилу скобок. Это означает, что, например, -f($file).".bak" эквивалентно -f "$file.bak".
См. также "Термы и операторы списков (влево)".
Операторы сравнения
Операторы Perl, которые возвращают true или false, обычно возвращают значения, которые можно безопасно использовать как числа. Например, операторы сравнения в этом разделе и операторы равенства в следующем возвращают 1 для true и специальную версию пустой строки, "", которая считается нулём, но исключена из предупреждений об ошибочных числовых преобразованиях, так же как и "0 but true".
Бинарный оператор "<" возвращает true, если левый аргумент численно меньше правого.
Бинарный оператор ">" возвращает true, если левый аргумент численно больше правого.
Бинарный оператор "<=" возвращает true, если левый аргумент численно меньше или равен правому.
Бинарный оператор ">=" возвращает true, если левый аргумент численно больше или равен правому.
Бинарный оператор "lt" возвращает true, если левый аргумент меньше правого в лексикографическом порядке.
Бинарный оператор "gt" возвращает true, если левый аргумент больше правого в лексикографическом порядке.
Бинарный оператор "le" возвращает true, если левый аргумент меньше или равен правому в лексикографическом порядке.
Бинарный оператор "ge" возвращает true, если левый аргумент больше или равен правому в лексикографическом порядке.
Последовательность операторов сравнения, например, "$x < $y <= $z", выполняет цепочечные сравнения, как описано выше в разделе "Приоритет операторов и ассоциативность". Будьте осторожны, так как они не образуют цепочки с операторами равенства, у которых более низкий приоритет.
Операторы равенства
Бинарный оператор "==" возвращает true, если левый аргумент численно равен правому.
Бинарный оператор "!=" возвращает true, если левый аргумент численно не равен правому.
Бинарный оператор "eq" возвращает true, если левый аргумент равен правому в лексикографическом порядке.
Бинарный оператор "ne" возвращает true, если левый аргумент не равен правому в лексикографическом порядке.
Последовательность вышеперечисленных операторов равенства, таких как "$x == $y == $z", выполняет цепочечные сравнения, как описано выше в разделе "Приоритет операторов и ассоциативность". Будьте осторожны, так как они не образуют цепочки с операторами сравнения, у которых более высокий приоритет.
Бинарный оператор "<=>" возвращает -1, 0 или 1, в зависимости от того, меньше, равно или больше левый аргумент, чем правый. Если ваша платформа поддерживает значения NaN (не число) как числовые значения, использование их с "<=>" возвращает undef. NaN — это не "<", "==", ">", "<=" или ">=" что-либо (даже NaN), поэтому эти 5 возвращают false. NaN != NaN возвращает true, как и NaN != любое другое значение. Если ваша платформа не поддерживает NaN, то NaN — это просто строка с числовым значением 0.
$ perl -le '$x = "NaN"; print "No NaN support here" if $x == $x'
$ perl -le '$x = "NaN"; print "NaN support here" if $x != $x' (Обратите внимание, что псевдонимы bigint, bigrat и bignum поддерживают "NaN".)
Бинарный оператор "cmp" возвращает -1, 0 или 1, в зависимости от того, меньше, равно или больше левый аргумент, чем правый в лексикографическом порядке.
Здесь мы видим разницу между <=> и cmp,
print 10 <=> 2 #prints 1
print 10 cmp 2 #prints -1 (аналогично между gt и >, lt и < и т. д.)
Бинарный оператор "~~" выполняет умное соответствие между своими аргументами. Умное соответствие описано в следующем разделе.
Двусторонние операторы упорядочения "<=>" и "cmp", и оператор умного соответствия "~~", не являются ассоциативными друг с другом и с операторами равенства той же приоритетности.
"lt", "le", "ge", "gt" и "cmp" используют порядок сортировки (сортировку) указанный текущим LC_COLLATE языком, если в силе use locale формат, включающий сортировку. См. perllocale. Не смешивайте эти операторы с Unicode, используйте их только с 8-битными кодировками языков.
Стандартные модули Unicode::Collate и Unicode::Collate::Locale предлагают гораздо более мощные решения для проблем сортировки.
Для сравнений, не учитывающих регистр, посмотрите на функцию преобразования регистра "fc" в perlfunc, доступную в Perl v5.16 или более поздних версиях:
if ( fc($x) eq fc($y) ) { ... } Оператор проверки класса
Бинарный оператор isa принимает значение true, когда левый аргумент является экземпляром объекта класса (или подкласса, производного от этого класса), заданного правым аргументом. Если левый аргумент не определён, не является экземпляром благословлённого объекта, либо не производным от класса, заданного правым аргументом, оператор принимает значение false. Правый аргумент может задавать класс в виде слова или скалярного выражения, возвращающего имя класса в виде строки:
if( $obj isa Some::Class ) { ... }
if( $obj isa "Different::Class" ) { ... }
if( $obj isa $name_of_class ) { ... } Эта функция доступна начиная с Perl 5.31.6 при включении use feature 'isa'. Эта функция включается автоматически при объявлении use v5.36 (или выше) в текущем объёме.
Оператор Smartmatch
Впервые доступен в Perl 5.10.1 (версия 5.10.0 имела другое поведение), бинарный ~~ выполняет "умное сравнение" между своими аргументами. Это в основном используется неявно в конструкции when , описанной в perlsyn, хотя не все when пункты вызывают оператор smartmatch. В отличие от всех других операторов Perl, оператор smartmatch может рекурсировать. Оператор smartmatch является экспериментальным и его поведение может измениться.
Он также уникален тем, что все другие операторы Perl накладывают контекст (обычно строковый или числовой) на свои операнды, автоматически преобразуя эти операнды в наложенные контексты. В отличие от этого, smartmatch выводит контексты из фактических типов своих операндов и использует эту информацию о типе для выбора подходящего механизма сравнения.
Оператор ~~ сравнивает свои операнды "полиморфно", определяя, как сравнивать их в соответствии с их фактическими типами (числовой, строковый, массив, хэш и т. д.). Как и операторы равенства, с которыми он имеет одинаковый приоритет, ~~ возвращает 1 для истинного и "" для ложного. Его часто лучше произносить вслух как "в", "внутри" или "содержит", потому что левый операнд часто ищется внутри правого операнда. Это делает порядок операндов для оператора smartmatch часто противоположным порядку оператора обычного сравнения. Другими словами, "меньшая" вещь обычно размещается в левом операнде, а большая - в правом.
Поведение smartmatch зависит от типа вещей, которые являются его аргументами, как указано в следующей таблице. Первый ряд таблицы, типы которого применяются, определяет поведение smartmatch. Поскольку то, что фактически происходит, в основном определяется типом второго операнда, таблица отсортирована по правому операнду, а не по левому.
Left Right Description and pseudocode
===============================================================
Any undef check whether Any is undefined
like: !defined Any
Any Object invoke ~~ overloading on Object, or die
Right operand is an ARRAY:
Left Right Description and pseudocode
===============================================================
ARRAY1 ARRAY2 recurse on paired elements of ARRAY1 and ARRAY2[2]
like: (ARRAY1[0] ~~ ARRAY2[0])
&& (ARRAY1[1] ~~ ARRAY2[1]) && ...
HASH ARRAY any ARRAY elements exist as HASH keys
like: grep { exists HASH->{$_} } ARRAY
Regexp ARRAY any ARRAY elements pattern match Regexp
like: grep { /Regexp/ } ARRAY
undef ARRAY undef in ARRAY
like: grep { !defined } ARRAY
Any ARRAY smartmatch each ARRAY element[3]
like: grep { Any ~~ $_ } ARRAY
Right operand is a HASH:
Left Right Description and pseudocode
===============================================================
HASH1 HASH2 all same keys in both HASHes
like: keys HASH1 ==
grep { exists HASH2->{$_} } keys HASH1
ARRAY HASH any ARRAY elements exist as HASH keys
like: grep { exists HASH->{$_} } ARRAY
Regexp HASH any HASH keys pattern match Regexp
like: grep { /Regexp/ } keys HASH
undef HASH always false (undef cannot 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)
Right operand is a Regexp:
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. Либо фактическое число, либо строка, которая выглядит как число.
Оператор smartmatch неявно делает dereference любого не-благословенного хеша или ссылки на массив, поэтому записи HASH и ARRAY применяются в этих случаях. Для благословенных ссылок применяются записи Object. При сравнении хешей учитываются только ключи хеша, никогда не значения.
Запись кода "like" не всегда является точным отображением. Например, оператор smartmatch выполняет короткое замыкание всякий раз, когда это возможно, но grep этого не делает. Кроме того, grep в скалярном контексте возвращает количество совпадений, но ~~ возвращает только true или false.
В отличие от большинства операторов, оператор smartmatch знает, как обращаться со undef особенно:
use v5.10.1;
@array = (1, 2, 3, undef, 4, 5);
say "some elements undefined" if undef ~~ @array; Каждый операнд рассматривается в изменённом скалярном контексте, изменение заключается в том, что массивы и хэши передаются в оператор по ссылке, который неявно делает dereference. Оба элемента каждой пары одинаковы:
use v5.10.1;
my %hash = (red => 1, blue => 2, green => 3,
orange => 4, yellow => 5, purple => 6,
black => 7, grey => 8, white => 9);
my @array = qw(red blue green);
say "some array elements in hash keys" if @array ~~ %hash;
say "some array elements in hash keys" if \@array ~~ \%hash;
say "red in array" if "red" ~~ @array;
say "red in array" if "red" ~~ \@array;
say "some keys end in e" if /e$/ ~~ %hash;
say "some keys end in e" if /e$/ ~~ \%hash; Два массива совпадают, если каждый элемент в первом массиве выполняет умное сравнение (то есть, "в") соответствующего элемента во втором массиве, рекурсивно.
use v5.10.1;
my @little = qw(red blue green);
my @bigger = ("red", "blue", [ "orange", "green" ] );
if (@little ~~ @bigger) { # true!
say "little is contained in bigger";
} Поскольку оператор smartmatch рекурсивно выполняется над вложенными массивами, это всё ещё сообщит, что "красный" находится в массиве.
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, перегрузка может быть или не быть вызвана. Для простых строк или чисел "в" становится эквивалентным этому:
$object ~~ $number ref($object) == $number
$object ~~ $string ref($object) eq $string Например, это сообщает, что ручка пахнет IOish (но, пожалуйста, не делайте этого!):
use IO::Handle;
my $fh = IO::Handle->new();
if ($fh ~~ /\bIO\b/) {
say "handle smells IOish";
} Потому что он обрабатывает $fh как строку, подобную "IO::Handle=GLOB(0x8039e0)", затем выполняет сопоставление с образцом.
Побитовое И
Бинарный оператор "&" возвращает свои операнды, побитовое И которых взято. Хотя в настоящее время предупреждение не выдаётся, результат не определён, когда эта операция выполняется над операндами, которые не являются числами (см. "Целочисленная арифметика") или битовыми строками (см. "Побитовые строковые операторы").
Обратите внимание, что "&" имеет более низкий приоритет, чем операторы сравнения, поэтому, например, скобки необходимы в тесте типа
print "Even\n" if ($x & 1) == 0; Если функция "побитовое" включена с помощью use feature 'bitwise' или use v5.28, то этот оператор всегда обрабатывает свои операнды как числа. До Perl 5.28 эта функция выдавала предупреждение в категории "experimental::bitwise".
Побитовое ИЛИ и исключающее ИЛИ
Бинарный "|" возвращает свои операнды, побитовое ИЛИ которых взято.
Бинарный "^" возвращает свои операнды, побитовое исключающее ИЛИ которых взято.
Хотя в настоящее время предупреждение не выдаётся, результаты не определённы, когда эти операции выполняются над операндами, которые не являются числами (см. "Целочисленная арифметика") или битовыми строками (см. "Побитовые строковые операторы").
Обратите внимание, что "|" и "^" имеют более низкий приоритет, чем операторы сравнения, поэтому, например, скобки необходимы в тесте типа
print "false\n" if (8 | 2) != 10; Если функция "побитовое" включена с помощью use feature 'bitwise' или use v5.28, то этот оператор всегда обрабатывает свои операнды как числа. До Perl 5.28 эта функция выдавала предупреждение в категории "experimental::bitwise".
Логическое И (стиль C)
Бинарный "&&" выполняет операцию короткого замыкания логического И. То есть, если левый операнд ложный, правый операнд даже не оценивается. Скалярный или списочный контекст передаётся правому операнду, если он оценивается.
Логическое ИЛИ (стиль C)
Бинарный "||" выполняет операцию короткого замыкания логического ИЛИ. То есть, если левый операнд истинный, правый операнд даже не оценивается. Скалярный или списочный контекст передаётся правому операнду, если он оценивается.
Логическое ИЛИ (определение)
Хотя у него нет прямого эквивалента в C, оператор Perl // связан с его C-стилевым "или". Фактически, он точно такой же, как ||, за исключением того, что он проверяет определённость левой части вместо её истинности. Таким образом, EXPR1 // EXPR2 возвращает значение EXPR1 , если оно определено, в противном случае возвращается значение EXPR2. (EXPR1 вычисляется в скалярном контексте, EXPR2 в контексте самого //). Обычно это тот же результат, что и defined(EXPR1) ? EXPR1 : EXPR2 (кроме того, что тройная форма оператора может использоваться как lvalue, а EXPR1 // EXPR2 - нет). Это очень полезно для предоставления значений по умолчанию для переменных. Если вы хотите проверить, определено ли хотя бы одно из $x и $y, используйте defined($x // $y).
Операторы ||, // и && возвращают последнее вычисленное значение (в отличие от C || и &&, которые возвращают 0 или 1). Таким образом, достаточно переносимый способ узнать домашний каталог может быть:
$home = $ENV{HOME}
// $ENV{LOGDIR}
// (getpwuid($<))[7]
// die "You're homeless!\n"; В частности, это означает, что вы не должны использовать это для выбора между двумя агрегатами для присваивания:
@a = @b || @c; # This doesn't do the right thing
@a = scalar(@b) || @c; # because it really means this.
@a = @b ? @b : @c; # This works fine, though. В качестве альтернатив && и || при использовании для управления потоком, Perl предоставляет операторы and и or (см. ниже). Поведение короткого замыкания идентично. Однако приоритет "and" и "or" намного ниже, поэтому вы можете безопасно использовать их после оператора списка без скобок:
unlink "alpha", "beta", "gamma"
or gripe(), next LINE; С операторами в стиле C, которые были бы написаны так:
unlink("alpha", "beta", "gamma")
|| (gripe(), next LINE); Было бы ещё понятнее написать это так:
unless(unlink("alpha", "beta", "gamma")) {
gripe();
next LINE;
} Использование "or" для присваивания вряд ли даст желаемый результат; см. ниже.
Операторы диапазона
Бинарный оператор ".." — это оператор диапазона, который на самом деле представляет собой два разных оператора в зависимости от контекста. В списковом контексте он возвращает список значений, считая (с шагом 1) от левого значения до правого. Если левое значение больше правого, то возвращается пустой список. Оператор диапазона полезен для написания foreach (1..10) циклов и для выполнения операций среза над массивами. В текущей реализации временный массив не создаётся, когда оператор диапазона используется в качестве выражения в foreach циклах, но более старые версии Perl могут тратить много памяти, если вы напишете что-то вроде этого:
for (1 .. 1_000_000) {
# code
} Оператор диапазона также работает со строками, используя магический автоматический инкремент, см. ниже.
В скалярном контексте ".." возвращает булево значение. Оператор является бистабильным, как триггер, и эмулирует оператор диапазона строк (запятая) в sed, awk и различных редакторах. Каждый ".." оператор сохраняет своё собственное булево состояние, даже при вызовах подпрограммы, которая его содержит. Он ложен до тех пор, пока его левый операнд ложен. Как только левый операнд становится истинным, оператор диапазона остаётся истинным до тех пор, пока правый операнд не станет истинным, после чего оператор диапазона снова становится ложным. Он не становится ложным до следующего момента оценки оператора диапазона. Он может проверить правый операнд и стать ложным в той же самой оценке, в которой он стал истинным (как в awk), но он всё равно возвращает истинное значение один раз. Если вы не хотите, чтобы он проверял правый операнд до следующей оценки, как в sed, просто используйте три точки ("...") вместо двух. Во всех других отношениях "..." ведёт себя так же, как "..".
Правый операнд не оценивается, пока оператор находится в состоянии «ложь», а левый операнд не оценивается, пока оператор находится в состоянии «истина». Приоритет немного ниже, чем || и &&. Возвращаемое значение — либо пустая строка для ложного значения, либо номер последовательности (начиная с 1) для истинного значения. Номер последовательности сбрасывается для каждого встреченного диапазона. Последний номер последовательности в диапазоне имеет строку "E0", добавленную к нему, что не влияет на его числовое значение, но даёт вам что-то, за чем можно искать, если вы хотите исключить конечную точку. Вы можете исключить начальную точку, дождавшись, чтобы номер последовательности стал больше 1.
Если любой операнд скалярного ".." является константным выражением, этот операнд считается истинным, если он равен (==) текущему номеру строки ввода (переменная $.).
Чтобы быть педантичным, сравнение фактически int(EXPR) == int(EXPR), но это проблема только если вы используете выражение с плавающей точкой; при неявном использовании $. как описано в предыдущем абзаце, сравнение является int(EXPR) == int($.), что является проблемой только тогда, когда $. установлено в значение с плавающей точкой, и вы не читаете из файла. Кроме того, "span" .. "spat" или 2.18 .. 3.14 не сделают того, что вы хотите в скалярном контексте, потому что каждый из операндов оценивается с использованием их целочисленного представления.
Примеры:
В качестве скалярного оператора:
if (101 .. 200) { print; } # print 2nd hundred lines, short for
# if ($. == 101 .. $. == 200) { print; }
next LINE if (1 .. /^$/); # skip header lines, short for
# next LINE if ($. == 1 .. /^$/);
# (typically in a loop labeled LINE)
s/^/> / if (/^$/ .. eof()); # quote body
# parse mail messages
while (<>) {
$in_header = 1 .. /^$/;
$in_body = /^$/ .. eof;
if ($in_header) {
# do something
} else { # in body
# do something else
}
} continue {
close ARGV if eof; # reset $. each file
} Вот простой пример, чтобы проиллюстрировать разницу между двумя операторами диапазона:
@lines = (" - Foo",
"01 - Bar",
"1 - Baz",
" - Quux");
foreach (@lines) {
if (/0/ .. /1/) {
print "$_\n";
}
} Эта программа будет печатать только строку, содержащую «Bar». Если оператор диапазона изменить на ..., она также выведет строку «Baz».
И теперь некоторые примеры в качестве оператора списка:
for (101 .. 200) { print } # print $_ 100 times
@foo = @foo[0 .. $#foo]; # an expensive no-op
@foo = @foo[$#foo-4 .. $#foo]; # slice last 5 items Поскольку каждый операнд оценивается в целочисленном виде, 2.18 .. 3.14 вернёт два элемента в контексте списка.
@list = (2.18 .. 3.14); # same as @list = (2 .. 3); Оператор диапазона в контексте списка может использовать магический алгоритм автоматического инкремента, если оба операнда являются строками, при соблюдении следующих правил:
-
За одним исключением (ниже), если обе строки похожи на числа в Perl, магический инкремент не будет применён, и строки будут обработаны как числа (точнее, целые числа) вместо этого.
Например,
"-2".."2"то же самое, что-2..2, и"2.18".."3.14"даёт2, 3. -
Исключение из этого правила — когда левая строка начинается с
0и длиннее одного символа, в этом случае магический инкремент будет применён, даже если строки типа"01"обычно воспринимались бы Perl как числа.Например,
"01".."04"даёт"01", "02", "03", "04", и"00".."-1"даёт"00"по"99"— это может показаться удивительным, но см. следующие правила, объясняющие, почему так происходит. Чтобы получить даты с ведущими нулями, можно сказать:@z2 = ("01" .. "31"); print $z2[$mday];Если вы хотите принудительно интерпретировать строки как числа, вы можете сказать
@numbers = ( 0+$first .. 0+$last );Примечание: В версиях Perl 5.30 и ниже любая строка в левой части, начинающаяся с
"0", включая саму строку"0", вызывала бы поведение магического инкремента строк. Это означает, что в этих версиях Perl"0".."-1"давало бы"0"по"99", что было несовместимо с0..-1, которое даёт пустой список. Это также означает, что"0".."9"теперь даёт список целых чисел вместо списка строк. -
Если заданное начальное значение не является частью последовательности магического инкремента (то есть непустой строкой, соответствующей
/^[a-zA-Z]*[0-9]*\z/), возвращается только начальное значение.Например,
"ax".."az"даёт"ax", "ay", "az", но"*x".."az"даёт только"*x". -
Для других начальных значений, которые являются строками, которые следуют правилам магического инкремента, возвращается соответствующая последовательность.
Например, вы можете сказать
@alphabet = ("A" .. "Z");чтобы получить все обычные буквы английского алфавита, или
$hexdigit = (0 .. 9, "a" .. "f")[$num & 15];чтобы получить шестнадцатеричную цифру.
-
Если конечное значение не входит в последовательность, которую генерирует магический инкремент, последовательность продолжается до тех пор, пока следующее значение не станет длиннее конечного значения. Если длина конечной строки короче первой, возвращается пустой список.
Например,
"a".."--"то же самое, что"a".."zz","0".."xx"даёт"0"по"99", и"aaa".."--"возвращает пустой список.
Начиная с Perl 5.26, оператор диапазона в списковом контексте для строк работает как ожидается в рамках "use feature 'unicode_strings". В предыдущих версиях, и вне области действия этой функции, он демонстрирует "Проблему Unicode" в perlunicode: его поведение зависит от внутреннего кодирования конечной точки диапазона.
Поскольку магический инкремент работает только с непустыми строками, соответствующими /^[a-zA-Z]*[0-9]*\z/, следующее вернёт только alpha:
use charnames "greek";
my @greek_small = ("\N{alpha}" .. "\N{omega}"); Чтобы получить 25 традиционных строчных греческих букв, включая обе сигмы, можно вместо этого использовать:
use charnames "greek";
my @greek_small = map { chr } ( ord("\N{alpha}")
..
ord("\N{omega}")
); Однако, поскольку существует множество других строчных греческих символов, помимо этих, чтобы сопоставить строчные греческие символы в регулярном выражении, вы можете использовать шаблон /(?:(?=\p{Greek})\p{Lower})+/ (или экспериментальную функцию /(?[ \p{Greek} & \p{Lower} ])+/).
Условный оператор
Тернарный оператор "?:" — это условный оператор, как и в C. Он работает примерно как оператор if-then-else. Если аргумент перед ? истинное, возвращается аргумент перед :, иначе возвращается аргумент после :. Например:
printf "I have %d dog%s.\n", $n,
($n == 1) ? "" : "s"; Скалярный или списковый контекст распространяется вниз на 2-й или 3-й аргумент, какой из них выбран.
$x = $ok ? $y : $z; # get a scalar
@x = $ok ? @y : @z; # get an array
$x = $ok ? @y : @z; # oops, that's just a count! Оператор можно присвоить, если и 2-й, и 3-й аргументы являются левыми значениями (то есть вы можете присвоить им значения):
($x_or_y ? $x : $y) = $z; Поскольку этот оператор производит присваиваемое значение, использование присваиваний без скобок приведёт к проблемам. Например, это:
$x % 2 ? $x += 10 : $x += 2 На самом деле означает это:
(($x % 2) ? ($x += 10) : $x) += 2 А не это:
($x % 2) ? ($x += 10) : ($x += 2) Это, вероятно, лучше записать проще как:
$x += ($x % 2) ? 10 : 2; Операторы присваивания
"=" — обычный оператор присваивания.
Операторы присваивания работают как в C. То есть,
$x += 2; эквивалентно
$x = $x + 2; хотя и без дублирования каких-либо побочных эффектов, которые могут возникнуть при разыменовании левого значения, таких как в tie(). Аналогичным образом работают и другие операторы присваивания. Признаются следующие:
**= += *= &= &.= <<= &&=
-= /= |= |.= >>= ||=
.= %= ^= ^.= //=
x= Хотя они сгруппированы по семействам, все они имеют приоритет присваивания. Эти комбинированные операторы присваивания могут работать только со скалярами, в то время как обычный оператор присваивания может присваивать массивам, хешам, спискам и даже ссылкам. (См. "Контекст" и "Конструкторы списковых значений" в perldata, и "Присваивание ссылкам" в perlref.)
В отличие от C, скалярный оператор присваивания производит действительное левое значение. Изменение присваивания равносильно выполнению присваивания, а затем изменению переменной, которой было присвоено значение. Это полезно для изменения копии чего-либо, например так:
($tmp = $global) =~ tr/13579/24680/; Хотя, начиная с версии 5.14, это можно сделать и так:
use v5.14;
$tmp = ($global =~ tr/13579/24680/r); Аналогично,
($x += 2) *= 3; эквивалентно
$x += 2;
$x *= 3; Точно так же, присвоение списка в контексте списка производит список левых значений, присвоенных значениям, а присвоение списка в скалярном контексте возвращает число элементов, произведённых выражением в правой части присваивания.
Три оператора побитового присваивания с точками (&.= |.= ^.=) являются новыми в Perl 5.22. См. "Операторы побитового сравнения строк".
Оператор запятой
Бинарный оператор "," — это оператор запятой. В скалярном контексте он вычисляет свой левый аргумент, отбрасывает это значение, затем вычисляет свой правый аргумент и возвращает это значение. Это то же самое, что и оператор запятой в C.
В контексте списка это просто разделитель аргументов списка и вставляет оба своих аргумента в список. Эти аргументы также вычисляются слева направо.
Оператор => (иногда произносится «жирная запятая») — это синоним запятой, за исключением того, что он заставляет слово слева интерпретироваться как строка, если оно начинается с буквы или нижнего подчёркивания и состоит только из букв, цифр и нижних подчёркиваний. Это включает операнды, которые в противном случае могли бы интерпретироваться как операторы, константы, одно числовые v-строки или вызовы функций. Если вы сомневаетесь в этом поведении, левым операндом можно явно воспользоваться.
В противном случае оператор => ведёт себя точно так же, как оператор запятой или разделитель аргументов списка, в зависимости от контекста.
Например:
use constant FOO => "something";
my %h = ( FOO => 23 ); эквивалентно:
my %h = ("FOO", 23); Это НЕ:
my %h = ("something", 23); Оператор => полезен для документирования соответствия между ключами и значениями в хэшах и другими парными элементами в списках.
%hash = ( $key => $value );
login( $username => $password ); Специальное поведение цитирования игнорирует приоритет и, следовательно, может применяться к части левого операнда:
print time.shift => "bbb"; Этот пример выводит что-то вроде "1314363215shiftbbb", потому что => неявно цитирует shift непосредственно слева, игнорируя тот факт, что time.shift является целым левым операндом.
Операторы списков (вправо)
В правой части оператора списка запятая имеет очень низкий приоритет, таким образом она контролирует все выражения, разделенные запятыми, которые там находятся. Единственными операторами с более низким приоритетом являются логические операторы "and", "or", и "not", которые могут использоваться для оценки вызовов операторов списка без скобок:
open HANDLE, "< :encoding(UTF-8)", "filename"
or die "Can't open: $!\n"; Однако некоторые люди находят этот код сложнее для чтения, чем написание с использованием скобок:
open(HANDLE, "< :encoding(UTF-8)", "filename")
or die "Can't open: $!\n"; В этом случае вы можете просто использовать более обычный оператор %%%CODE_BLOCK_501%%:
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 shown: SMILEY)
\x{ 263A } Same, but shows optional blanks inside and
adjoining the braces
\x1b [2,8] restricted range hex char (example: ESC)
\N{name} [3] named Unicode character or character sequence
\N{U+263D} [4,8] Unicode character (example: FIRST QUARTER MOON)
\c[ [5] control char (example: chr(27))
\o{23072} [6,8] octal char (example: SMILEY)
\033 [7,8] restricted range octal char (example: ESC) Обратите внимание, что любая escape-последовательность, использующая фигурные скобки внутри интерполируемых конструкций, может иметь необязательные пробелы (символы табуляции или пробела), прилегающие к ним и внутри них, как показано выше на втором примере \x{ }.
- [1]
-
Результат — символ, указанный шестнадцатеричным числом в фигурных скобках. Подробности о том, какой символ это будет, см. в "[8]" ниже.
Пробелы (символы табуляции или пробела) могут отделять число от фигурных скобок.
В противном случае между фигурными скобками допустимы только шестнадцатеричные цифры. Если встречен недопустимый символ, будет выведено предупреждение, и недопустимый символ, а также все последующие символы (допустимые или нет) внутри фигурных скобок будут отброшены.
Если между фигурными скобками нет допустимых цифр, генерируемый символ — символ NULL (
\x{00}). Однако явный пустой набор фигурных скобок (\x{}) не вызовет предупреждения (пока). - [2]
-
Результат — символ, заданный шестнадцатеричным числом в диапазоне от 0x00 до 0xFF. Подробности о том, какой символ это будет, см. в "[8]" ниже.
После
\xдопустимы только шестнадцатеричные цифры. Когда\xследует меньше двух допустимых цифр, любые допустимые цифры будут дополнены нулями. Это означает, что\x7будет интерпретироваться как\x07, а одиночное"\x"— как\x00. За исключением конца строки, наличие меньше двух допустимых цифр приведет к предупреждению. Обратите внимание, что, хотя предупреждение говорит о том, что недопустимый символ игнорируется, он игнорируется только как часть escape-последовательности и по-прежнему будет использоваться как последующий символ в строке. Например:Original Result Warns? "\x7" "\x07" no "\x" "\x00" no "\x7q" "\x07q" yes "\xq" "\x00q" yes - [3]
-
Результат — символ Unicode или последовательность символов, заданная значением name. См. charnames.
- [4]
-
\N{U+hexadecimal number}означает символ Unicode, у которого код Unicode — шестнадцатеричное число. - [5]
-
Символ, следующий за
\c, отображается на другой символ, как показано в таблице:Sequence Value \c@ chr(0) \cA chr(1) \ca chr(1) \cB chr(2) \cb chr(2) ... \cZ chr(26) \cz chr(26) \c[ chr(27) # See below for chr(28) \c] chr(29) \c^ chr(30) \c_ chr(31) \c? chr(127) # (on ASCII platforms; see below for link to # EBCDIC discussion)Другими словами, это символ, код которого получен путём побитового исключающего ИЛИ с 64, применённым к его заглавной версии.
\c?— DELETE на платформах ASCII, потому чтоord("?") ^ 64— 127, а\c@— NULL, потому что ord от"@"— 64, поэтому побитовое исключающее ИЛИ с 64 даёт 0.Также,
\c\Xдаётchr(28) . "X"для любого X, но не может стоять в конце строки, поскольку обратный слэш был бы интерпретирован как экранирование закрывающей кавычки.На платформах ASCII результирующие символы из приведенного выше списка — полный набор управляющих символов ASCII. Это не так на платформах EBCDIC; см. "OPERATOR DIFFERENCES" в perlebcdic для полного обсуждения различий между этими платформами для ASCII и EBCDIC.
Использование любых других символов после
"c"помимо перечисленных выше не рекомендуется, а с Perl v5.20 разрешены только печатаемые символы ASCII, за вычетом левой фигурной скобки"{". Что происходит для любых других допустимых символов, так это то, что значение выводится путём побитового исключающего ИЛИ с седьмым битом, который равен 64, а также выводится предупреждение, если оно включено. Использование недопустимых символов приводит к ошибке.Чтобы получить независимые от платформы управляющие символы, вы можете использовать
\N{...}. - [6]
-
Результат — символ, указанный восьмеричным числом в фигурных скобках. Подробности о том, какой символ это будет, см. в "[8]" ниже.
Пробелы (символы табуляции или пробела) могут отделять число от фигурных скобок.
В противном случае, если встречен символ, который не является восьмеричной цифрой, выводится предупреждение, и значение основано на восьмеричных цифрах перед ним, а символ и все следующие символы до закрывающей фигурной скобки отбрасываются. Ошибка, если вообще нет восьмеричных цифр.
- [7]
-
Результат — символ, указанный трёхзначным восьмеричным числом в диапазоне от 000 до 777 (но лучше не использовать значения выше 077, см. следующий абзац). Подробности о том, какой символ это будет, см. в "[8]" ниже.
В некоторых контекстах допустимы 2 или даже 1 цифра, но любое использование без ровно трёх цифр, первой из которых является ноль, может привести к непредвиденным результатам. (Например, в регулярном выражении это может быть спутано со ссылкой на обратную ссылку; см. "Octal escapes" в perlrebackslash.) Начиная с Perl 5.14, вы можете использовать
\o{}вместо этого, что избавляет от всех этих проблем. В противном случае лучше использовать эту конструкцию только для порядковых номеров\077и ниже, помня о необходимости дополнения нулями слева, чтобы получить три цифры. Для больших порядковых номеров используйте\o{}, или преобразуйте их в что-то другое, например, в шестнадцатеричное представление и используйте\N{U+}(что портабельно между платформами с различными наборами символов) или\x{}вместо этого. - [8]
-
Несколько конструкций выше указывают символ по числу. Это число соответствует положению символа в кодировке набора символов (индексировано с 0). Это также называется порядковым номером, кодовой позицией или кодовым значением. Perl работает на платформах, в которых родной кодировкой сейчас является ASCII/Latin1 или EBCDIC, каждый из которых позволяет указать 256 символов. В общем случае, если число равно 255 (0xFF, 0377) или меньше, Perl интерпретирует это в родной кодировке платформы. Если число равно 256 (0x100, 0400) или больше, Perl интерпретирует его как код Unicode, и результатом будет соответствующий символ Unicode. Например,
\x{50}и\o{120}— это число 80 в десятичной системе, которое меньше 256, поэтому число интерпретируется в кодировке набора символов платформы. В ASCII символ в 80-й позиции (индексированной с 0) — это буква"P", а в EBCDIC — символ амперсанда"&".\x{100}и\o{400}— оба равны 256 в десятичной системе, поэтому число интерпретируется как код Unicode независимо от родной кодировки. Название символа в 256-й позиции (индексированной с 0) в Unicode —LATIN CAPITAL LETTER A WITH MACRON.Исключением из этого правила является то, что
\N{U+hex number}всегда интерпретируется как код Unicode, поэтому\N{U+0050}—"P"даже на платформах EBCDIC.
ПРИМЕЧАНИЕ: В отличие от C и других языков, в Perl нет \v escape-последовательности для вертикальной табуляции (VT, которая равна 11 как в ASCII, так и в EBCDIC), но вы можете использовать \N{VT}, \N{U+0b}, или \x0b. (\v имеет значение в шаблонах регулярных выражений в Perl, см. perlre.)
Следующие escape-последовательности доступны в конструкциях, которые интерполируют, но не в транслитерациях.
\l lowercase next character only
\u titlecase (not uppercase!) next character only
\L lowercase all characters till \E or end of string
\U uppercase all characters till \E or end of string
\F foldcase all characters till \E or end of string
\Q quote (disable) pattern metacharacters till \E or
end of string
\E end either case modification or quoted section
(whichever was last seen) См. "quotemeta" в perlfunc для точного определения символов, которые цитируются с помощью \Q.
\L, \U, \F, и \Q могут стоять друг за другом, в этом случае вам нужен один \E для каждого. Например:
say "This \Qquoting \ubusiness \Uhere isn't quite\E done yet,\E is it?";
This quoting\ Business\ HERE\ ISN\'T\ QUITE\ done\ yet\, is it? Если в действии форма use locale, включающая LC_CTYPE, (см. perllocale), используемая карта символов для \l, \L, \u, и \U берется из текущего региональных настроек. Если используется Unicode (например, \N{} или коды символов 0x100 или более), используемая карта символов для \l, \L, \u, и \U определяется Unicode. Это означает, что преобразование в верхний регистр одного символа иногда может привести к последовательности нескольких символов. В use locale, \F производит те же результаты, что и \L для всех регионов, кроме UTF-8, где он вместо этого использует определение Unicode.
Все системы используют виртуальный "\n" для представления символа конца строки, называемого «новой строкой». Нет такого понятия, как неизменный физический символ новой строки. Это всего лишь иллюзия, которую операционная система, драйверы устройств, библиотеки C и Perl согласуются сохранять. Не все системы читают "\r" как ASCII CR и "\n" как ASCII LF. Например, на старых Mac (до MacOS X) эти символы использовались в обратном порядке, а на системах без символа конца строки вывод "\n" мог не передавать никаких данных. В общем случае используйте "\n" для обозначения «новой строки» для вашей системы, но используйте буквальный ASCII, если вам нужен точный символ. Например, большинство сетевых протоколов ожидают и предпочитают CR+LF ("\015\012" или "\cM\cJ") для символов конца строки, и хотя они часто принимают только "\012", они редко терпят только "\015". Если вы привыкнете использовать "\n" для работы в сети, вы можете однажды об этом пожалеть.
Для конструкций, которые интерполируют, переменные, начинающиеся с "$" или "@", интерполируются. Также интерполируются индексированные переменные, такие как $a[3] или $href->{key}[0], а также срезы массивов и словарей. Но вызовы методов, такие как $obj->meth, не интерполируются.
Интерполяция массива или среза интерполирует элементы в порядке, разделяя их значением $", что эквивалентно интерполяции join $", @array. «Пунктуационные» массивы, такие как @*, обычно интерполируются только если имя заключено в фигурные скобки @{*}, но массивы @_, @+, и @- интерполируются даже без фигурных скобок.
Для строковых литералов в двойных кавычках цитирование из \Q применяется после интерполяции и обработки escape-последовательностей.
"abc\Qfoo\tbar$s\Exyz" эквивалентно
"abc" . quotemeta("foo\tbar$s") . "xyz" Для шаблона операторов регулярных выражений (qr//, m// и s///), цитирование из \Q применяется после обработки интерполяции, но до обработки escape-последовательностей. Это позволяет шаблону соответствовать буквально (за исключением $ и @). Например, следующее соответствует:
'\s\t' =~ /\Q\s\t/ Поскольку $ или @ запускают интерполяцию, вам нужно использовать что-то вроде /\Quser\E\@\Qhost/ для соответствия им буквально.
Шаблоны подвергаются дополнительной интерпретации в качестве регулярных выражений. Это делается как вторая фаза после интерполяции переменных, чтобы регулярные выражения могли быть включены в шаблон из переменных. Если вы этого не хотите, используйте \Q для интерполяции переменной буквально.
Помимо описанного выше поведения, Perl не расширяет несколько уровней интерполяции. В частности, в отличие от ожиданий программистов оболочек, обратные кавычки НЕ интерполируют внутри двойных кавычек, и одинарные кавычки не препятствуют оценке переменных при использовании внутри двойных кавычек.
Операторы цитирования регулярных выражений
Ниже приведены операторы цитирования, применяемые к сопоставлению с шаблоном и связанным с ним действиям.
-
qr/STRING/msixpodualn -
Этот оператор приводит (и, возможно, компилирует) свой STRING в качестве регулярного выражения. STRING интерполируется так же, как PATTERN в
m/PATTERN/. Если"'"используется в качестве разделителя, интерполяция переменных не выполняется. Возвращает значение Perl, которое можно использовать вместо соответствующего/STRING/msixpodualnвыражения. Возвращаемое значение является нормализованной версией исходного шаблона. Оно магически отличается от строки, содержащей те же символы:ref(qr/x/)возвращает «Regexp»; однако, обращение к нему не определено (в настоящее время вы получаете нормализованную версию исходного шаблона, но это может измениться).Например,
$rex = qr/my.STRING/is; print $rex; # prints (?si-xm:my.STRING) s/$rex/foo/;эквивалентно
s/my.STRING/foo/is;Результат может быть использован как подшаблон в поиске совпадения:
$re = qr/$pattern/; $string =~ /foo${re}bar/; # can be interpolated in other # patterns $string =~ $re; # or used standalone $string =~ /$re/; # or this wayПоскольку Perl может скомпилировать шаблон в момент выполнения оператора
qr(), использованиеqr()может иметь преимущества в скорости в некоторых ситуациях, особенно если результатqr()используется автономно:sub match { my $patterns = shift; my @compiled = map qr/$_/i, @$patterns; grep { my $success = 0; foreach my $pat (@compiled) { $success = 1, last if /$pat/; } $success; } @_; }Предварительная компиляция шаблона во внутреннее представление в момент
qr()позволяет избежать необходимости повторной компиляции шаблона каждый раз, когда попытка совпадения/$pat/осуществляется. (Perl имеет множество других внутренних оптимизаций, но ни одна из них не будет запущена в приведённом выше примере, если мы не используем операторqr().)Параметры (указанные следующими модификаторами) являются:
m Treat string as multiple lines. s Treat string as single line. (Make . match a newline) i Do case-insensitive pattern matching. x Use extended regular expressions; specifying two x's means \t and the SPACE character are ignored within square-bracketed character classes p When matching preserve a copy of the matched string so that ${^PREMATCH}, ${^MATCH}, ${^POSTMATCH} will be defined (ignored starting in v5.20) as these are always defined starting in that release o Compile pattern only once. a ASCII-restrict: Use ASCII for \d, \s, \w and [[:posix:]] character classes; specifying two a's adds the further restriction that no ASCII character will match a non-ASCII one under /i. l Use the current run-time locale's rules. u Use Unicode rules. d Use Unicode or native charset, as in 5.12 and earlier. n Non-capture mode. Don't let () fill in $1, $2, etc...Если предварительно скомпилированный шаблон вставлен в более крупный шаблон, то эффект
"msixpluadn"будет распространяться соответствующим образом. Эффект модификатора/oне распространяется, будучи ограниченным теми шаблонами, которые его явно используют.Модификаторы
/a,/d,/l, и/u(добавлено в Perl 5.14) управляют правилами набора символов, но/a— единственный, который, скорее всего, нужно будет указать явно; остальные три выбираются автоматически различными прагмами.См. perlre для получения дополнительной информации о допустимом синтаксисе для STRING и для подробного рассмотрения семантики регулярных выражений. В частности, все модификаторы, кроме в значительной степени устаревшего
/o, более подробно описаны в "Modifiers" в perlre./oописан в следующем разделе. -
m/PATTERN/msixpodualngc -
/PATTERN/msixpodualngc -
Ищет в строке совпадение с шаблоном и в скалярном контексте возвращает true, если поиск успешен, и false, если нет. Если строка не указана с помощью оператора
=~или!~, ищется строка$_. (Строка, указанная с помощью=~не обязательно должна быть lvalue — она может быть результатом оценки выражения, но помните, что=~связывает довольно плотно.) См. также perlre.Параметры описаны в
qr//выше; кроме того, доступны следующие модификаторы процесса поиска совпадения:g Match globally, i.e., find all occurrences. c Do not reset search position on a failed match when /g is in effect.Если
"/"является разделителем, то начальныйmявляется необязательным. С помощьюmвы можете использовать любую пару не-пробельных (ASCII) символов в качестве разделителей. Это особенно полезно для поиска совпадений в именах путей, содержащих"/", чтобы избежать LTS (синдрома наклоненной зубочистки). Если"?"является разделителем, то применяется правило поиска только одного совпадения, описанное вm?PATTERN?ниже. Если"'"(одинарная кавычка) является разделителем, интерполяция переменных в PATTERN не выполняется. При использовании разделителя, являющегося допустимым символом идентификатора, после разделителя требуется пробел послеm.PATTERN может содержать переменные, которые будут интерполироваться каждый раз, когда выполняется поиск совпадения по шаблону, за исключением случаев, когда разделителем является одинарная кавычка. (Обратите внимание, что
$(,$), и$|не интерполируются, так как они выглядят как тесты на конец строки.) Perl не будет повторно компилировать шаблон, если изменённая интерполируемая переменная в шаблоне. Вы можете принудительно заставить Perl пропустить тест и никогда не перекомпилировать его, добавив/o(что означает "один раз") после заключительного разделителя. Когда-то Perl излишне перекомпилировал регулярные выражения, и этот модификатор был полезен, чтобы сказать ему этого не делать, в интересах скорости. Но сейчас единственными причинами использования/oявляются:-
Переменные имеют длину в тысячи символов, и вам известно, что они не меняются, и вам нужно выжать последнюю каплю скорости, заставив Perl пропустить проверку. (Существует штраф за обслуживание за это, так как упоминание
/oозначает обещание, что вы не измените переменные в шаблоне. Если вы их измените, Perl даже не заметит.) -
Вы хотите, чтобы шаблон использовал начальные значения переменных независимо от того, меняются ли они или нет. (Но есть более разумные способы достижения этого, чем использование
/o.) -
Если шаблон содержит встроенный код, такой как
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, то указанная строка должна быть скалярной переменной, элементом массива, элементом хеша или присваиванием одному из них; то есть, какой-либо скалярной lvalue.Если выбран разделитель, состоящий из одного символа апострофа, интерполяция переменных не выполняется ни для PATTERN, ни для REPLACEMENT. В противном случае, если PATTERN содержит
$, который выглядит как переменная, а не как тест на конец строки, переменная будет интерполирована в шаблон во время выполнения. Если вы хотите, чтобы шаблон был скомпилирован только один раз при первой интерполяции переменной, используйте параметр/o. Если шаблон принимает пустую строку, вместо этого используется последний успешно выполненный регулярный выражение. См. perlre для получения дополнительной информации об этом.Параметры совпадают с параметрами
m//с добавлением следующих параметров, специфичных для замены:e Evaluate the right side as an expression. ee Evaluate the right side as a string then eval the result. r Return substitution and leave the original string untouched.Любой разделитель, не являющийся пробелом, может заменить слэши. Добавьте пробел после
sпри использовании символа, разрешённого в идентификаторах. Если используются одинарные кавычки, интерпретация строки замены не выполняется (модификатор/eтем не менее переопределяет это). Обратите внимание, что Perl обрабатывает обратные кавычки как обычные разделители; текст замены не оценивается как команда. Если PATTERN ограничен скобочными кавычками, у REPLACEMENT есть своя пара кавычек, которые могут быть или не быть скобочными кавычками, например,s(foo)(bar)илиs<foo>/bar/./eзаставит часть замены быть обработана как полноценное выражение Perl и вычислено непосредственно на месте. Тем не менее, проверка синтаксиса выполняется во время компиляции. Второй модификаторeприведет к тому, что часть замены будетevalперед выполнением её как выражения Perl.Примеры:
s/\bgreen\b/mauve/g; # don't change wintergreen $path =~ s|/usr/bin|/usr/local/bin|; s/Login: $foo/Login: $bar/; # run-time pattern ($foo = $bar) =~ s/this/that/; # copy first, then # change ($foo = "$bar") =~ s/this/that/; # convert to string, # copy, then change $foo = $bar =~ s/this/that/r; # Same as above using /r $foo = $bar =~ s/this/that/r =~ s/that/the other/r; # Chained substitutes # using /r @foo = map { s/this/that/r } @bar # /r is very useful in # maps $count = ($paragraph =~ s/Mister\b/Mr./g); # get change-cnt $_ = 'abc123xyz'; s/\d+/$&*2/e; # yields 'abc246xyz' s/\d+/sprintf("%5d",$&)/e; # yields 'abc 246xyz' s/\w/$& x 2/eg; # yields 'aabbcc 224466xxyyzz' s/%(.)/$percent{$1}/g; # change percent escapes; no /e s/%(.)/$percent{$1} || $&/ge; # expr now, so /e s/^=(\w+)/pod($1)/ge; # use function call $_ = 'abc123xyz'; $x = s/abc/def/r; # $x is 'def123xyz' and # $_ remains 'abc123xyz'. # expand variables in $_, but dynamics only, using # symbolic dereferencing s/\$(\w+)/${$1}/g; # Add one to the value of any numbers in the string s/(\d+)/1 + $1/eg; # Titlecase words in the last 30 characters only (presuming # that the substring doesn't start in the middle of a word) substr($str, -30) =~ s/\b(\p{Alpha})(\p{Alpha}*)\b/\u$1\L$2/g; # This will expand any embedded scalar variable # (including lexicals) in $_ : First $1 is interpolated # to the variable name, and then evaluated s/(\$\w+)/$1/eeg; # Delete (most) C comments. $program =~ s { /\* # Match the opening delimiter. .*? # Match a minimal number of characters. \*/ # Match the closing delimiter. } []gsx; s/^\s*(.*?)\s*$/$1/; # trim whitespace in $_, # expensively for ($variable) { # trim whitespace in $variable, # cheap s/^\s+//; s/\s+$//; } s/([^ ]*) *([^ ]*)/$2 $1/; # reverse 1st two fields $foo !~ s/A/a/g; # Lowercase all A's in $foo; return # 0 if any were found and changed; # otherwise return 1Обратите внимание на использование
$вместо\в последнем примере. В отличие от sed, мы используем форму \<цифра> только в левой части. В любом другом месте это $<цифра>.Иногда вы не можете просто использовать
/g, чтобы получить все изменения, которые вы хотите. Вот два распространённых случая:# put commas in the right places in an integer 1 while s/(\d)(\d\d\d)(?!\d)/$1,$2/g; # expand tabs to 8-column spacing 1 while s/\t+/' ' x (length($&)*8 - length($`)%8)/e;Хотя
s///принимает флаг/c, он не оказывает никакого влияния, кроме как выдачи предупреждения, если включены предупреждения.
Операторы типа кавычек
-
q/STRING/ -
'STRING' -
Строка в одинарных кавычках, являющаяся литералом. Обратный слэш обозначает обратный слэш, если не следует разделитель или другой обратный слэш, в противном случае разделитель или обратный слэш интерполируются.
$foo = q!I said, "You said, 'She said it.'"!; $bar = q('This is it.'); $baz = '\n'; # a two-character string -
qq/STRING/ -
"STRING" -
Строка в двойных кавычках, с интерполяцией.
$_ .= qq (*** The previous line contains the naughty word "$1".\n) if /\b(tcl|java|python)\b/i; # :-) $baz = "\n"; # a one-character string -
qx/STRING/ -
`STRING` -
Строка, которая (возможно) интерполируется и затем выполняется как системная команда через /bin/sh или его эквивалент, если это необходимо. Будут учтены подстановки оболочки, конвейеры и перенаправления. Аналогично
system, если строка не содержит символов метаязыка оболочки, то она будет выполнена непосредственно. Возвращается собранный стандартный вывод команды; стандартная ошибка не затрагивается. В скалярном контексте возвращается одна (возможно, многострочная) строка илиundef, если оболочка (или команда) не могла быть запущена. В контексте списка возвращается список строк (как вы определили строки с$/или$INPUT_RECORD_SEPARATOR), или пустой список, если оболочка (или команда) не могла быть запущена.Поскольку обратные кавычки не влияют на стандартную ошибку, используйте синтаксис описателя файла оболочки (если оболочка поддерживает это), если вам нужно обработать эту ситуацию. Чтобы захватить 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 NTcmd).Perl попытается очистить все файлы, открытые для вывода, перед запуском дочернего процесса, но это может не поддерживаться на некоторых платформах (см. perlport). Для большей безопасности может потребоваться установить
$|($AUTOFLUSHвEnglish) или вызвать методautoflush()объектаIO::Handleдля любых открытых дескрипторов.Следует помнить, что некоторые оболочки команд могут устанавливать ограничения на длину командной строки. Вы должны убедиться, что ваши строки не превышают это ограничение после всех необходимых интерполяций. Подробнее об этом можно узнать из примечаний к выпуску для конкретной среды.
Использование этого оператора может привести к программам, которые трудно портировать, потому что вызываемые команды оболочки отличаются в разных системах и могут вообще отсутствовать. Например, команда
typeв оболочке POSIX сильно отличается от командыtypeв DOS. Это не означает, что вы должны избегать обратных кавычек, когда они являются правильным способом выполнения чего-либо. Perl был создан как язык связывания, и одной из связываемых им вещей являются команды. Просто поймите, в чём вы участвуете.Подобно
system, обратные кавычки помещают код выхода дочернего процесса в$?. Если вам нужно вручную проверить ошибки, вы можете проверить все возможные режимы ошибок, проверив$?таким образом:if ($? == -1) { print "failed to execute: $!\n"; } elsif ($? & 127) { printf "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without'; } else { printf "child exited with value %d\n", $? >> 8; }Используйте прагму open для управления слоями ввода-вывода при чтении вывода команды, например:
use open IN => ":encoding(UTF-8)"; my $x = `cmd-producing-utf-8`;qx//также может вызываться как функция с "readpipe" в perlfunc.Дополнительные обсуждения см. в "Операторах ввода-вывода".
-
qw/STRING/ -
Оценивается как список слов, извлечённых из STRING с использованием встроенных пробелов в качестве разделителей слов. Это можно примерно сравнить с:
split(" ", q/STRING/);Различия заключаются в том, что он разделяет только на пробелы ASCII, генерирует реальный список во время компиляции и в скалярном контексте возвращает последний элемент списка. Поэтому это выражение:
qw(foo bar baz)семантически эквивалентно списку:
"foo", "bar", "baz"Некоторые часто используемые примеры:
use POSIX qw( setlocale localeconv ) @EXPORT = qw( foo bar baz );Распространённой ошибкой является попытка разделить слова запятыми или вставить комментарии в многострочную строку
qw. По этой причине прагмаuse warningsи переключатель -w (т. е. переменная$^W) выдают предупреждения, если STRING содержит символы","или"#". -
tr/SEARCHLIST/REPLACEMENTLIST/cdsr -
y/SEARCHLIST/REPLACEMENTLIST/cdsr
-
Преобразует все вхождения символов, найденных (или не найденных, если указан модификатор
/c) в списке поиска, с соответствующим по позиции символом в списке замены, возможно удаляя некоторые, в зависимости от указанных модификаторов. Возвращает количество заменённых или удалённых символов. Если строка не указана через оператор=~или!~, транслитерируется строка$_.Для поклонников sed,
yпредоставляется как синоним дляtr.Если присутствует опция
/r(неразрушающая), создаётся новая копия строки и её символы транслитерируются, и эта копия возвращается, независимо от того, была ли она изменена или нет: исходная строка всегда остаётся неизменной. Новая копия всегда является простой строкой, даже если входная строка является объектом или привязанной переменной.Если не используется опция
/r, строка, указанная с помощью=~, должна быть скалярной переменной, элементом массива, элементом хеша или присваиванием одному из них; другими словами, lvalue.Символы, разделяющие СПИСОК_ПОИСКА и СПИСОК_ЗАМЕНЫ, могут быть любым печатным символом, а не только прямой косой чертой. Если это одинарные кавычки (
tr'SEARCHLIST'REPLACEMENTLIST'), единственная интерполяция — удаление\из пар\\; поэтому дефисы интерпретируются буквально, а не указывают диапазон символов.В противном случае, диапазон символов может быть указан с помощью дефиса, таким образом,
tr/A-J/0-9/выполняет ту же замену, что иtr/ACEGIBDFHJ/0246813579/.Если СПИСОК_ПОИСКА ограничен скобочными кавычками, СПИСОК_ЗАМЕНЫ должен иметь свою пару кавычек, которые могут быть или не быть скобочными кавычками; например,
tr(aeiouy)(yuoiea)илиtr[+\-*/]"ABCD". Этот последний пример показывает способ визуального уточнения того, что происходит для людей, более знакомых с шаблонами регулярных выражений, чем сtr, и которые могут подумать, что разделители прямой косой чертой подразумевают, чтоtrбольше похож на шаблон регулярного выражения, чем на самом деле. (Другим вариантом может быть использованиеtr[...][...].)trне полностью похож на скобочные классы символов, только (значительно) больше похож на них, чем на полные шаблоны. Например, символы, появляющиеся более одного раза в любом списке, ведут себя по-разному здесь, чем в шаблонах, а спискиtrне допускают обратных слэшей в классах символов, таких как\dили\pL, а также интерполяцию переменных, поэтому"$"и"@"всегда обрабатываются как литералы.Допустимые элементы — литералы плюс
\'(означает одиночную кавычку). Если разделители не одинарные кавычки, также допустимы любые из последовательностей escape, принятые в двойных кавычках. Подробности о последовательностях escape приведены в таблице в начале этого раздела.Дефис в начале или конце, или предшествующий обратной косой чертой, также всегда рассматривается как литерал. Чтобы разрешить символ разделителя, поместите перед ним обратную косую черту.
Оператор
trне эквивалентен утилитеtr(1).tr[a-z][A-Z]преобразует 26 букв от "a" до "z" в верхний регистр, но для изменения регистра, не ограничивающегося ASCII, используйтеlc,uc,lcfirst,ucfirst(все документированы в perlfunc) или оператор подстановкиs/PATTERN/REPLACEMENT/(с\U,\u,\L, и\lэкранирования интерполяции строк в части ЗАМЕНЫ).Большинство диапазонов не переносимы между наборами символов, но некоторые из них сигнализируют Perl о специальной обработке для обеспечения переносимости. Есть два класса переносимых диапазонов. Первые — любые подмножества диапазонов
A-Z,a-z, и0-9, когда они выражены как литеральные символы.tr/h-k/H-K/приводит буквы
"h","i","j", и"k"в верхний регистр, и ничего более, независимо от набора символов платформы. В противоположность этому, всеtr/\x68-\x6B/\x48-\x4B/ tr/h-\x6B/H-\x4B/ tr/\x68-k/\x48-K/выполняют те же преобразования в верхний регистр, что и предыдущий пример при выполнении на платформах ASCII, но совершенно другие на платформах EBCDIC.
Второй класс переносимых диапазонов вызывается, когда один или оба конечных точки диапазона выражены как
\N{...}.$string =~ tr/\N{U+20}-\N{U+7E}//d;удаляет из
$stringвсе символы платформы, которые эквивалентны любому из Unicode U+0020, U+0021, ... U+007D, U+007E. Это переносимый диапазон и имеет тот же эффект на каждой платформе, на которой он выполняется. В этом примере это печатные символы ASCII. Итак, после выполнения этого$stringсодержит только управляющие символы и символы, у которых нет эквивалентов ASCII.Но даже для переносимых диапазонов обычно не очевидно, что включено, без необходимости поиска в руководстве. Звуковым принципом является использование только диапазонов, которые начинаются и заканчиваются как ASCII буквами одинакового регистра (
b-e,B-E) или цифрами (1-4). Всё остальное неясно (и не переносимо, если не используется\N{...}). В случае сомнений, полностью распишите наборы символов.Параметры:
c Complement the SEARCHLIST. d Delete found but unreplaced characters. r Return the modified string and leave the original string untouched. s Squash duplicate replaced characters.Если указан модификатор
/d, любые символы, указанные в СПИСКЕ_ПОИСКА, которые не найдены в СПИСКЕ_ЗАМЕНЫ, удаляются. (Обратите внимание, что это немного гибче, чем поведение некоторых программ tr, которые удаляют всё, что находят в СПИСКЕ_ПОИСКА, точка).Если указан модификатор
/s, последовательности символов, все в строке, которые были преобразованы в один и тот же символ, сжимаются до единственного экземпляра этого символа.my $a = "aaabbbca"; $a =~ tr/ab/dd/s; # $a now is "dcd"Если используется модификатор
/d, СПИСОК_ЗАМЕНЫ всегда интерпретируется точно как указано. В противном случае, если СПИСОК_ЗАМЕНЫ короче СПИСКА_ПОИСКА, последний символ, если таковой имеется, дублируется до тех пор, пока он не станет достаточно длинным. Последний символ не будет, если и только если СПИСОК_ЗАМЕНЫ пуст, в этом случае СПИСОК_ЗАМЕНЫ копируется из СПИСКА_ПОИСКА. Пустой СПИСОК_ЗАМЕНЫ полезен для подсчёта символов в классе или для сжатия последовательностей символов в классе.tr/abcd// tr/abcd/abcd/ tr/abcd/AB/ tr/abcd/ABBB/ tr/abcd//d s/[abcd]//g tr/abcd/AB/d (tr/ab/AB/ + s/[cd]//g) - but run togetherЕсли указан модификатор
/c, символы, которые будут транслитерированы, — это символы, НЕ в СПИСКЕ_ПОИСКА, то есть, он дополняется. Если/dи/или/sтакже указаны, они применяются к дополненному СПИСКУ_ПОИСКА. Помните, что если СПИСОК_ЗАМЕНЫ пуст (кроме случаев/d), СПИСОК_ЗАМЕНЫ заменяется копией СПИСКА_ПОИСКА (как модифицированного в/c). Эти потенциально изменённые списки используются в качестве основы для последующего. Любой символ в целевой строке, который не находится в СПИСКЕ_ПОИСКА, передаётся без изменений. Каждый другой символ в целевой строке заменяется символом в СПИСКЕ_ЗАМЕНЫ, который позиционно соответствует его партнёру в СПИСКЕ_ПОИСКА, за исключением того, что в/s, второй и последующие символы выдавливаются в последовательности символов в строке, которые все преобразуются в один и тот же символ. Если СПИСОК_ПОИСКА длиннее СПИСКА_ЗАМЕНЫ, символы в целевой строке, которые соответствуют символу в СПИСКЕ_ПОИСКА, у которого нет соответствия в СПИСКЕ_ЗАМЕНЫ, либо удаляются из целевой строки, если указан/d; или заменяются последним символом в СПИСКЕ_ЗАМЕНЫ, если не указан/d.Примеры:
$ARGV[1] =~ tr/A-Z/a-z/; # canonicalize to lower case ASCII $cnt = tr/*/*/; # count the stars in $_ $cnt = tr/*//; # same thing $cnt = $sky =~ tr/*/*/; # count the stars in $sky $cnt = $sky =~ tr/*//; # same thing $cnt = $sky =~ tr/*//c; # count all the non-stars in $sky $cnt = $sky =~ tr/*/*/c; # same, but transliterate each non-star # into a star, leaving the already-stars # alone. Afterwards, everything in $sky # is a star. $cnt = tr/0-9//; # count the ASCII digits in $_ tr/a-zA-Z//s; # bookkeeper -> bokeper tr/o/o/s; # bookkeeper -> bokkeeper tr/oe/oe/s; # bookkeeper -> bokkeper tr/oe//s; # bookkeeper -> bokkeper tr/oe/o/s; # bookkeeper -> bokkopor ($HOST = $host) =~ tr/a-z/A-Z/; $HOST = $host =~ tr/a-z/A-Z/r; # same thing $HOST = $host =~ tr/a-z/A-Z/r # chained with s///r =~ s/:/ -p/r; tr/a-zA-Z/ /cs; # change non-alphas to single space @stripped = map tr/a-zA-Z/ /csr, @original; # /r with map tr [\200-\377] [\000-\177]; # wickedly delete 8th bit $foo !~ tr/A/a/ # transliterate all the A's in $foo to 'a', # return 0 if any were found and changed. # Otherwise return 1Если для символа задано несколько транслитераций, используется только первая:
tr/AAA/XYZ/будет транслитерировать любую A в X.
Поскольку таблица транслитерации создаётся во время компиляции, ни СПИСОК_ПОИСКА, ни СПИСОК_ЗАМЕНЫ не подвергаются интерполяции двойных кавычек. Это означает, что если вы хотите использовать переменные, вы должны использовать
eval().eval "tr/$oldlist/$newlist/"; die $@ if $@; eval "tr/$oldlist/$newlist/, 1" or die $@; -
<<EOF
-
Строковый способ цитирования основан на синтаксисе оболочки "here-document". После
<<вы указываете строку для завершения цитируемого материала, и все строки, следующие за текущей строкой до строки завершения, являются значением элемента.Представление строки завершения с помощью
~указывает, что вы хотите использовать "Вложенные здесь-документы" (см. ниже).Строка завершения может быть либо идентификатором (словом), либо каким-то цитируемым текстом. Нецитируемый идентификатор работает как двойные кавычки. Между
<<и идентификатором не должно быть пробела, если идентификатор не является явно цитируемым. Строка завершения должна быть расположена сама по себе (не цитированная и без окружающих пробелов) в строке завершения.Если строка завершения цитируется, тип используемых кавычек определяет обработку текста.
- Двойные кавычки
-
Двойные кавычки указывают, что текст будет интерполирован с использованием точно таких же правил, как обычные двойные кавычки.
print <<EOF; The price is $Price. EOF print << "EOF"; # same as above The price is $Price. EOF - Одинарные кавычки
-
Одинарные кавычки указывают, что текст должен обрабатываться буквально без интерполяции его содержимого. Это аналогично строкам в одинарных кавычках, за исключением того, что обратные слэши не имеют специального значения, при этом
\\рассматривается как два обратных слэша, а не как один, как в других конструкциях цитирования.Как и в оболочке, обратный слэш, за которым следует голый идентификатор после
<<, означает то же самое, что и строка в одинарных кавычках:$cost = <<'VISTA'; # hasta la ... That'll be $10 please, ma'am. VISTA $cost = <<\VISTA; # Same thing! That'll be $10 please, ma'am. VISTAЭто единственный способ цитирования в Perl, где нет необходимости беспокоиться об экранировании содержимого, что кодогенераторы могут и используют эффективно.
- Обратные кавычки
-
Содержимое здесь-документа обрабатывается так же, как если бы строка была вставлена в обратные кавычки. Таким образом, содержимое интерполируется как будто оно было в двойных кавычках, а затем выполняется через оболочку, и результаты выполнения возвращаются.
print << `EOC`; # execute command and get results echo hi there EOC
- Вложенные здесь-документы
-
Модификатор здесь-документа
~позволяет вставлять отступы в ваши здесь-документы, чтобы код был более читабельным:if ($some_var) { print <<~EOF; This is a here-doc EOF }Это будет выводить...
This is a here-doc...без ведущих пробелов.
Строка, содержащая разделитель, обозначающий конец здесь-документа, определяет шаблон отступа для всего. Компилятор выдаст ошибку, если любая непустая строка внутри здесь-документа не начинается с точного отступа строки завершения. (Пустая строка состоит из единственного символа "\n".) Например, предположим, что строка завершения начинается с символа табуляции, за которым следуют 4 пробела. Каждая непустая строка в здесь-документе должна начинаться с символа табуляции, за которым следуют 4 пробела. Они удаляются из каждой строки, а любые оставшиеся ведущие пробелы в строке служат отступом для этой строки. В настоящее время только символы ТАБУЛЯЦИИ и ПРОБЕЛА обрабатываются как пробелы для этой цели. Табуляции и пробелы могут быть смешаны, но должны точно совпадать; табуляции остаются табуляциями и не расширяются.
Дополнительные начальные пробелы (сверх тех, что предшествовали разделителю) будут сохранены:
print <<~EOF; This text is not indented This text is indented with two spaces This text is indented with two tabs EOFНаконец, модификатор может быть использован со всеми вышеупомянутыми формами:
<<~\EOF; <<~'EOF' <<~"EOF" <<~`EOF`И пробелы могут быть использованы между
~и цитируемыми разделителями:<<~ 'EOF'; # ... "EOF", `EOF`
Возможна последовательность нескольких здесь-документов:
print <<"foo", <<"bar"; # you can stack them I said foo. foo I said bar. bar myfunc(<< "THIS", 23, <<'THAT'); Here's a line or two. THIS and here's another. THATТолько не забудьте поставить точку с запятой в конце, чтобы закончить оператор, так как Perl не знает, что вы не собираетесь это сделать:
print <<ABC 179231 ABC + 20;Если вы хотите удалить символ конца строки из своих здесь-документов, используйте
chomp().chomp($string = <<'END'); This is a string. ENDЕсли вы хотите, чтобы ваши здесь-документы были отформатированы с отступом с остальной частью кода, используйте конструкцию
<<~FOO, описанную в разделе "Вложенные здесь-документы":$quote = <<~'FINIS'; The Road goes ever on and on, down from the door where it began. FINISЕсли вы используете здесь-документ внутри ограниченной конструкции, например, в
s///eg, цитируемый материал должен все равно находиться в строке, следующей за маркером<<FOO, что означает, что он может находиться внутри ограниченной конструкции:s/this/<<E . 'that' the other E . 'more '/eg;Это работает таким образом начиная с Perl 5.18. Исторически это было несовместимо, и вам нужно было писать
s/this/<<E . 'that' . 'more '/eg; the other Eвне вычислений строк.
Кроме того, правила цитирования для идентификатора конца строки не связаны с правилами цитирования Perl.
q(),qq(), и аналогичные не поддерживаются вместо''и"", и единственная интерполяция — для экранирования символа цитирования:print << "abc\"def"; testing... abc"defНаконец, цитируемые строки не могут занимать несколько строк. Общее правило состоит в том, что идентификатор должен быть строковым литералом. Придерживайтесь этого, и вы будете в безопасности.
Подробности парсинга цитируемых конструкций
Когда перед Perl ставится что-то, что может иметь несколько интерпретаций, Perl использует принцип DWIM (это "Do What I Mean") для выбора наиболее вероятной интерпретации. Эта стратегия настолько успешна, что программисты Perl часто не подозревают о неоднозначности того, что они пишут. Но время от времени взгляды Perl существенно отличаются от того, что автор искренне имел в виду.
Этот раздел призван прояснить, как Perl обрабатывает цитируемые конструкции. Хотя наиболее частая причина для изучения этого — разобраться в запутанных регулярных выражениях, поскольку начальные этапы парсинга одинаковы для всех операторов цитирования, все они рассматриваются вместе.
Самое важное правило парсинга Perl — первое, о котором будет сказано ниже: при обработке цитируемой конструкции Perl сначала находит конец этой конструкции, а затем интерпретирует ее содержимое. Если вы понимаете это правило, вы можете пропустить остальную часть этого раздела при первом чтении. Другие правила, скорее всего, будут противоречить ожиданиям пользователя гораздо реже, чем это первое.
Некоторые обсуждаемые этапы выполняются параллельно, но поскольку их результаты одинаковы, мы рассматриваем их по отдельности. Для разных конструкций цитирования Perl выполняет разное количество проходов, от одного до четырех, но эти проходы всегда выполняются в одном и том же порядке.
- Поиск конца
-
Первый проход — поиск конца цитируемой конструкции. Это приводит к сохранению в безопасном месте копии текста (между начальными и конечными разделителями), нормализованного по мере необходимости, чтобы не нужно было знать, какими были исходные разделители.
Если конструкция является здесь-документом, разделитель окончания — это строка, содержащая строку завершения в качестве содержимого. Поэтому
<<EOFзавершаетсяEOFсразу после"\n"и начиная с первого столбца строки завершения. При поиске строки завершения здесь-документа ничего не пропускается. Другими словами, строки после синтаксиса здесь-документа сравниваются со строкой завершения строка за строкой.Для конструкций, кроме здесь-документов, используются отдельные символы в качестве начальных и конечных разделителей. Если начальный разделитель — открывающая пунктуация (то есть
(,[,{, или<), конечный разделитель — соответствующая закрывающая пунктуация (то есть),],}, или>). Если начальный разделитель — несбалансированный символ, например/, или закрывающая пунктуация, то конечный разделитель такой же, как начальный. Поэтому/завершает конструкциюqq//, в то время как]завершает какqq[], так иqq]]конструкции.При поиске разделителей отдельных символов, экранированные разделители и
\\пропускаются. Например, при поиске завершающего/, комбинации\\и\/пропускаются. Если разделители — скобки, также пропускаются вложенные пары. Например, при поиске закрывающей], сопоставленной с открывающей[, комбинации\\,\], и\[пропускаются, а также вложенные[и]пропускаются. Однако, когда обратные слэши используются в качестве разделителей (например,qq\\иtr\\\), ничего не пропускается. Во время поиска конца обратные слэши, которые экранируют разделители или другие обратные слэши, удаляются (точно говоря, они не копируются в безопасное место).Для конструкций с трёхчастными разделителями (
s///,y///, иtr///), поиск повторяется ещё раз. Если первый разделитель не является открывающей пунктуацией, то три разделителя должны быть одинаковыми, напримерs!!!иtr))), в этом случае второй разделитель завершает левую часть и сразу начинает правую часть. Если левая часть ограничена скобочными знаками пунктуации (то есть(),[],{}, или<>), правой части необходима другая пара разделителей, таких какs(){}иtr[]//. В этих случаях пробелы и комментарии допускаются между двумя частями, хотя комментарий должен следовать как минимум за одним пробелом; в противном случае символ, ожидаемый как начало комментария, может рассматриваться как начальный разделитель правой части.При этом поиске не обращается внимания на семантику конструкции. Таким образом:
"$hash{"$foo/$bar"}"или:
m/ bar # NOT a comment, this slash / terminated m//! /xне образуют корректных цитируемых выражений. Цитируемая часть заканчивается на первом
"и/, и остальное оказывается синтаксической ошибкой. Поскольку слеш, который завершилm//, был послеSPACE, указанный выше пример не являетсяm//x, а скорееm//без модификатора/x. Таким образом, вложенный#интерпретируется как буквальный#.Также при этом поиске не обращается внимания на
\c\(синтаксис символов управления multichar). Таким образом, второй\вqq/\c\/интерпретируется как часть\/, а следующий/не распознается как разделитель. Вместо этого используйте\034или\x1cв конце цитируемых конструкций. - Интерполяция
-
Следующим шагом является интерполяция в полученном тексте, который теперь независим от разделителя. Существует несколько случаев.
-
<<'EOF' -
Интерполяция не выполняется. Обратите внимание, что сочетание
\\остается неизменным, так как экранированные разделители недоступны для here-документов. -
m'', шаблонs''' -
Интерполяция на данном этапе не выполняется. Любые последовательности с обратным слэшем, включая
\\, обрабатываются на стадии "Парсинга регулярных выражений". -
'',q//,tr''',y''', заменаs''' -
Единственная интерполяция — удаление
\из пар\\. Таким образом,"-"вtr'''иy'''обрабатывается буквально как дефис, и диапазон символов недоступен.\1в заменеs'''не работает как$1. -
tr///,y/// -
Интерполяция переменных не происходит. Комбинации для изменения строк в зависимости от регистра и кавычек, такие как
\Q,\U, и\E, не распознаются. Другие escape-последовательности, такие как\200и\t, и символы с обратным слэшем, такие как\\и\-, преобразуются в соответствующие литералы. Символ"-"обрабатывается особым образом, поэтому\-обрабатывается как литерал"-". -
"",``,qq//,qx//,<file*glob>,<<"EOF" -
\Q,\U,\u,\L,\l,\F(возможно, в паре с\E) преобразуются в соответствующие конструкции Perl. Таким образом,"$foo\Qbaz$bar"преобразуется в$foo . (quotemeta("baz" . $bar))внутри. Другие escape-последовательности, такие как\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присутствует).Парсинг конструкции скобочной группы символов
[...]отличается от правила, используемого для остальной части шаблона. Терминатор этой конструкции находится с помощью тех же правил, что и для поиска терминатора{}-ограниченной конструкции, единственным исключением является то, что]непосредственно после[обрабатывается так, как если бы перед ним стоял обратный слэш.Терминатор runtime
(?{...})находится путём временного переключения управления на парсер Perl, который должен остановиться в тот момент, когда логически совпадающий завершающий}будет найден.Можно просмотреть как строку, переданную движку RE, так и результирующий конечный автомат. См. аргументы
debug/debugcolorв директивеuse re, а также флаг командной строки Perl -Dr, описанный в "Флаги командной строки" в perlrun. - Оптимизация регулярных выражений
-
Этот шаг включён для полноты картины. Поскольку он не изменяет семантику, подробности этого шага не документированы и могут быть изменены без предварительного уведомления. Этот шаг выполняется над конечным автоматом, сгенерированным на предыдущем этапе.
Именно на этом этапе
split()молча оптимизирует/^/до значения/^/m.
Операторы Ввода-Вывода
Вам следует ознакомиться с несколькими операторами ввода-вывода.
Строка, заключённая в обратные кавычки (греческие акценты), сначала проходит интерполяцию двойных кавычек. Затем она интерпретируется как внешняя команда, и результат выполнения этой команды становится значением строки в обратных кавычках, как в оболочке. В скалярном контексте возвращается единственная строка, содержащая весь вывод. В контексте списка возвращается список значений, по одному на каждую строку вывода. (Вы можете установить $/ для использования другого разделителя строк.) Команда выполняется каждый раз при оценке псевдолитерала. Значение состояния команды возвращается в $? (см. perlvar для интерпретации $?). В отличие от csh, никакой перевод данных не выполняется — новые строки остаются новыми строками. В отличие от любой оболочки, одинарные кавычки не скрывают имена переменных в команде от интерпретации. Чтобы передать буквальный символ доллара в оболочку, необходимо скрыть его с помощью обратного слэша. Обобщённая форма обратных кавычек — qx//, или вы можете вызвать функцию "readpipe" в perlfunc. (Поскольку обратные кавычки всегда проходят расширение оболочки, см. perlsec для вопросов безопасности.)
В скалярном контексте вычисление дескриптора файла в угловых скобках возвращает следующую строку из этого файла (включая символ новой строки, если таковой имеется), или undef при достижении конца файла или возникновении ошибки. Когда $/ установлено в undef (иногда это называют режимом «чтения всего файла»), и файл пуст, оно возвращает '' в первый раз, а затем undef в последующие.
Обычно вам необходимо присвоить возвращаемое значение переменной, но есть одна ситуация, где происходит автоматическое присвоение. Если и только если входной символ является единственным элементом внутри условия оператора while (даже если он замаскирован в виде цикла for(;;)), значение автоматически присваивается глобальной переменной $_, уничтожая предыдущее значение. (Это может показаться странным, но вы будете использовать эту конструкцию практически во всех ваших скриптах Perl.) Переменная $_ не неявно локальна. Вам нужно поместить local $_; перед циклом, если вы хотите, чтобы это произошло. Кроме того, если входной символ или явное присваивание входного символа скаляру используется как условие while/for, то условие фактически проверяет определённость значения выражения, а не его обычное истинностное значение.
Таким образом, следующие строки эквивалентны:
while (defined($_ = <STDIN>)) { print; }
while ($_ = <STDIN>) { print; }
while (<STDIN>) { print; }
for (;<STDIN>;) { print; }
print while defined($_ = <STDIN>);
print while ($_ = <STDIN>);
print while <STDIN>; Это также работает аналогично, но присваивает значение лексической переменной вместо $_:
while (my $line = <STDIN>) { print $line } В этих циклических конструкциях присвоенное значение (автоматическое или явное) проверяется на определение. Проверка на определение избегает проблем, когда строка имеет строковое значение, которое Perl расценивает как ложь; например, "" или "0" без завершающей новой строки. Если вы действительно хотите, чтобы такие значения завершали цикл, их нужно явно проверять:
while (($_ = <STDIN>) ne '0') { ... }
while (<STDIN>) { last unless $_; ... } В других контекстах булевых значений <FILEHANDLE> без явной проверки defined или сравнения вызовет предупреждение, если используется директива use warnings или командная строка -w (переменная $^W).
Дескрипторы файлов STDIN, STDOUT и STDERR предопределены. (Дескрипторы файлов stdin, stdout, и stderr также будут работать, за исключением пакетов, где они будут интерпретироваться как локальные идентификаторы, а не глобальные.) Дополнительные дескрипторы файлов можно создать с помощью функции open(), среди прочих. Подробнее об этом см. perlopentut и "open" в perlfunc.
Если <FILEHANDLE> используется в контексте, ожидающем список, возвращается список, содержащий все строки ввода, по одной строке на элемент списка. Легко можно получить довольно большой объём данных таким образом, поэтому используйте с осторожностью.
<FILEHANDLE> также может быть написано как readline(*FILEHANDLE). См. "readline" в perlfunc.
Дескриптор файла <> (иногда называемый оператором ромба) является особым: он может использоваться для эмуляции поведения sed и awk, и любого другого unix-фильтра, принимающего список имён файлов, выполняя одинаковые действия над каждой строкой ввода из всех этих файлов. Ввод из <> поступает либо со стандартного ввода, либо из каждого файла, указанного в командной строке. Вот как это работает: при первой оценке <>, массив @ARGV проверяется, и если он пуст, $ARGV[0] устанавливается в "-", который при открытии даёт вам стандартный ввод. Затем массив @ARGV обрабатывается как список имён файлов. Цикл
while (<>) {
... # code for each line
} эквивалентен следующему псевдокоду Perl:
unshift(@ARGV, '-') unless @ARGV;
while ($ARGV = shift) {
open(ARGV, $ARGV);
while (<ARGV>) {
... # code for each line
}
} за исключением того, что он не так громоздко записан и на самом деле будет работать. Он действительно сдвигает массив @ARGV и помещает текущее имя файла в переменную $ARGV. Он также использует дескриптор файла ARGV внутри. <> — просто синоним <ARGV>, который является магическим. (Псевдокод выше не работает, потому что он рассматривает <ARGV> как не-магический.)
Поскольку нулевой дескриптор файла использует двухаргументную форму "open" в perlfunc, он интерпретирует специальные символы, поэтому, если у вас есть скрипт такого вида:
while (<>) {
print;
} и вы вызываете его с perl dangerous.pl 'rm -rfv *|', он фактически открывает канал, выполняет команду rm и считывает вывод rm из этого канала. Если вы хотите, чтобы все элементы в @ARGV интерпретировались как имена файлов, вы можете использовать модуль ARGV::readonly из CPAN или использовать двойные угловые скобки:
while (<<>>) {
print;
} Использование двойных угловых скобок внутри цикла while заставляет open использовать трёхаргументную форму (где второй аргумент — <), поэтому все аргументы в ARGV рассматриваются как буквальные имена файлов (включая "-"). (Обратите внимание, что для удобства, если вы используете <<>>, и если @ARGV пусто, он всё равно будет считывать со стандартного ввода.)
Вы можете изменить @ARGV перед первым <>, пока массив содержит список имен файлов, которые вам действительно нужны. Номера строк ($.) продолжаются, как будто ввод — один большой счастливый файл. См. пример в "eof" в perlfunc, чтобы узнать, как сбрасывать номера строк для каждого файла.
Если вы хотите установить @ARGV в свой собственный список файлов, пожалуйста, сделайте это. Это устанавливает @ARGV для всех текстовых файлов, если не было указано @ARGV:
@ARGV = grep { -f && -T } glob('*') unless @ARGV; Вы даже можете установить их на команды обработки. Например, это автоматически фильтрует сжатые аргументы через gzip:
@ARGV = map { /\.(gz|Z)$/ ? "gzip -dc < $_ |" : $_ } @ARGV; Если вы хотите передать параметры в свой скрипт, вы можете использовать один из модулей Getopts или поместить цикл в начало, как в этом примере:
while ($_ = $ARGV[0], /^-/) {
shift;
last if /^--$/;
if (/^-D(.*)/) { $debug = $1 }
if (/^-v/) { $verbose++ }
# ... # other switches
}
while (<>) {
# ... # code for each line
} Символ <> вернёт значение undef только при достижении конца файла. Если вы вызовете его снова после этого, он предположит, что вы обрабатываете другой список @ARGV, и если вы не задали @ARGV, будет читать ввод со стандартного ввода.
Если в угловых скобках находится простая скалярная переменная (например, $foo), то эта переменная содержит имя дескриптора файла для ввода, его типглоб или ссылку на то же самое. Например:
$fh = \*STDIN;
$line = <$fh>; Если содержимое в угловых скобках не является дескриптором файла и не является простой скалярной переменной, содержащей имя дескриптора файла, типглоб или ссылку на типглоб, оно интерпретируется как шаблон имени файла для подстановки и возвращает либо список имён файлов, либо следующее имя файла в списке, в зависимости от контекста. Это различие определяется только на синтаксическом уровне. Это означает, что <$x> всегда представляет собой readline() от косвенного дескриптора, но <$hash{key}> всегда является glob(). Это потому, что $x — простая скалярная переменная, но $hash{key} — нет, это элемент хеша. Даже <$x > (обратите внимание на дополнительный пробел) рассматривается как glob("$x "), а не readline($x).
Сначала выполняется один уровень интерпретации двойных кавычек, но вы не можете написать <$foo>, потому что это косвенный дескриптор файла, как объяснялось в предыдущем абзаце. (В старых версиях Perl программисты вставляли фигурные скобки, чтобы принудительно интерпретировать это как подстановку имени файла: <${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, $_;
} за исключением того, что подстановка имени файла фактически выполняется внутри с использованием стандартного расширения File::Glob. Конечно, самый короткий способ сделать это —
chmod 0644, <*.c>; Подстановка (файла) имени файла оценивает свой (встроенный) аргумент только при начале нового списка. Все значения должны быть прочитаны, прежде чем он начнёт заново. В контексте списка это не важно, потому что вы автоматически получаете их все. Однако в скалярном контексте оператор возвращает следующее значение каждый раз, когда он вызывается, или undef при исчерпании списка. Как и при чтении дескриптора файла, автоматическое присвоение defined генерируется, когда подстановка происходит в части условия while, потому что законное возвращение подстановки (например, файл с именем 0) в противном случае завершит цикл. Опять же, undef возвращается только один раз. Таким образом, если вы ожидаете одно значение от подстановки имени файла, гораздо лучше сказать
($file) = <blurch*>; чем
$file = <blurch*>; потому что последнее будет попеременно возвращать имя файла и ложь.
Если вы пытаетесь выполнить интерполяцию переменных, лучше использовать функцию glob(), потому что более старая запись может сбить с толку косвенным обозначением дескриптора файла.
@files = glob("$dir/*.[ch]");
@files = glob($files[$i]); Если выражение подстановки имени файла в угловых скобках используется в качестве условия цикла while или for, то оно неявно присваивается переменной $_. Если выражение подстановки имени файла или явное присваивание выражения подстановки имени файла скаляру используется как условие while/for, то условие фактически проверяет определённость значения выражения, а не его обычное истинностное значение.
Складывание констант
Как и в C, Perl выполняет определённую оценку выражений во время компиляции всякий раз, когда определяет, что все аргументы оператора являются статическими и не имеют побочных эффектов. В частности, конкатенация строк происходит во время компиляции между литералами, не выполняющими подстановку переменных. Интерполяция обратной косой черты также происходит во время компиляции. Можно сказать
'Now is the time for all'
. "\n"
. 'good men to come to.' и всё это сводится к одной строке во внутренней форме. Точно так же, если вы скажете
foreach $file (@filenames) {
if (-s $file > 5 + 100 * 2**16) { }
} компилятор предварительно вычисляет число, которое представляет это выражение, чтобы интерпретатор не должен был этого делать.
Операторы без действия
В Perl официально нет оператора без действия, но голые константы 0 и 1 являются специальными случаями, которые не генерируют предупреждение в контексте void, так что вы можете, например, безопасно выполнить
1 while foo(); Битовые операторы над строками
Битовые строки любого размера могут быть обработаны с помощью битовых операторов (~ | & ^).
Если операнды битового оператора – это строки разной длины, операторы | и ^ ведут себя так, как будто более короткая строка имела дополнительные нулевые биты справа, а оператор & – как будто более длинная строка была усечена до длины более короткой. Разрешение для такого расширения или усечения составляет один или несколько байтов.
# ASCII-based examples
print "j p \n" ^ " a h"; # prints "JAPH\n"
print "JA" | " ph\n"; # prints "japh\n"
print "japh\nJunk" & '_____'; # prints "JAPH\n";
print 'p N$' ^ " E<H\n"; # prints "Perl\n"; Если вы намерены обрабатывать битовые строки, убедитесь, что вы предоставляете битовые строки: если операнд является числом, это подразумевает числовую битовую операцию. Вы можете явно указать, какой тип операции вы намереваетесь выполнить, используя "" или 0+, как показано в примерах ниже.
$foo = 150 | 105; # yields 255 (0x96 | 0x69 is 0xFF)
$foo = '150' | 105; # yields 255
$foo = 150 | '105'; # yields 255
$foo = '150' | '105'; # yields string '155' (under ASCII)
$baz = 0+$foo & 0+$bar; # both ops explicitly numeric
$biz = "$foo" ^ "$bar"; # both ops explicitly stringy Это несколько непредсказуемое поведение можно избежать с помощью функции «битовый», новой в Perl 5.22. Вы можете включить её с помощью use feature 'bitwise' или use v5.28. До Perl 5.28, она выводила предупреждение в категории "experimental::bitwise". С этой функцией четыре стандартных битовых оператора (~ | & ^) всегда являются числовыми. Добавление точки после каждого оператора (~. |. &. ^.) заставляет его рассматривать свои операнды как строки:
use feature "bitwise";
$foo = 150 | 105; # yields 255 (0x96 | 0x69 is 0xFF)
$foo = '150' | 105; # yields 255
$foo = 150 | '105'; # yields 255
$foo = '150' | '105'; # yields 255
$foo = 150 |. 105; # yields string '155'
$foo = '150' |. 105; # yields string '155'
$foo = 150 |.'105'; # yields string '155'
$foo = '150' |.'105'; # yields string '155'
$baz = $foo & $bar; # both operands numeric
$biz = $foo ^. $bar; # both operands stringy Вспомогательные операторы присваивания с этими операторами (&= |= ^= &.= |.= ^.=) ведут себя аналогично в рамках данной функции.
Ошибка при выполнении операции, если операнд содержит символ, значение кода которого больше 0xFF, и поэтому его нельзя представить, кроме как в UTF-8. Операция выполняется над копии, не использующей UTF-8, для других операндов, закодированных в UTF-8. См. "Семантика байтов и символов" в perlunicode.
См. "vec" в perlfunc для получения информации о том, как манипулировать отдельными битами в битовом векторе.
Целочисленная арифметика
По умолчанию Perl предполагает, что ему нужно выполнять большинство арифметических операций с плавающей точкой. Но сказав
use integer; вы можете сказать компилятору использовать целочисленные операции (см. integer для подробного объяснения) отсюда до конца содержащего блока. Внутренний блок может отменить это, сказав
no integer; что сохраняется до конца этого блока. Обратите внимание, что это не означает, что всё является целым числом, а только то, что Perl будет использовать целочисленные операции для арифметических, сравнительных и битовых операторов. Например, даже при use integer, если вы возьмёте sqrt(2), вы всё равно получите 1.4142135623731 или около того.
При использовании с числами битовые операторы (& | ^ ~ << >>) всегда дают целочисленные результаты. (Но см. также "Битовые операторы над строками".) Однако use integer всё ещё имеет значение для них. По умолчанию их результаты интерпретируются как целые без знака, но если use integer действует, их результаты интерпретируются как целые со знаком. Например, ~0 обычно оценивается как большое целочисленное значение. Однако use integer; ~0 равно -1 на машинах с дополнением до двух.
Арифметика с плавающей точкой
Хотя use integer обеспечивает только целочисленную арифметику, нет аналогичного механизма для автоматического округления или усечения до определённого числа десятичных знаков. Для округления до определённого числа знаков sprintf() или printf() обычно является самым простым путём. См. perlfaq4.
Числа с плавающей точкой – это лишь приближения к тому, что математик называет действительными числами. Действительных чисел бесконечно больше, чем чисел с плавающей точкой, поэтому некоторые приближения неизбежны. Например:
printf "%.20g\n", 123456789123456789;
# produces 123456789123456784 Проверка точного равенства или неравенства чисел с плавающей точкой – не лучшая идея. Вот обходной путь (относительно дорогой), чтобы сравнить, равны ли два числа с плавающей точкой определённому числу десятичных знаков. Для более надёжной обработки этой темы см. Кнута, том II.
sub fp_equal {
my ($X, $Y, $POINTS) = @_;
my ($tX, $tY);
$tX = sprintf("%.${POINTS}g", $X);
$tY = sprintf("%.${POINTS}g", $Y);
return $tX eq $tY;
} Модуль POSIX (входит в стандартную поставку Perl) реализует ceil(), floor(), и другие математические и тригонометрические функции. Модуль Math::Complex (входит в стандартную поставку Perl) определяет математические функции, которые работают как с действительными, так и с комплексными числами. Math::Complex не так эффективен, как POSIX, но POSIX не может работать с комплексными числами.
Округление в финансовых приложениях может иметь серьёзные последствия, и метод округления должен быть чётко определён. В таких случаях, вероятно, не стоит доверять методу округления, используемому Perl, но лучше самостоятельно реализовать необходимую функцию округления.
Более крупные числа
Стандартные Math::BigInt, Math::BigRat, и Math::BigFloat модули, наряду с bignum, bigint, и bigrat псевдонимами, предоставляют арифметику с переменной точностью и перегруженные операторы, хотя они пока довольно медленные. Стоимость некоторых ресурсов и существенной скорости позволяет избежать обычных проблем, связанных с ограниченной точностью представления.
use 5.010;
use bigint; # easy interface to Math::BigInt
$x = 123456789123456789;
say $x * $x;
+15241578780673678515622620750190521 Или с рациональными числами:
use 5.010;
use bigrat;
$x = 3/22;
$y = 4/6;
say "x/y is ", $x/$y;
say "x*y is ", $x*$y;
x/y is 9/44
x*y is 1/11 Несколько модулей позволяют производить вычисления с неограниченной или фиксированной точностью (ограниченной только памятью и временем ЦП). Также существуют некоторые нестандартные модули, которые предоставляют более быстрые реализации через внешние библиотеки C.
Вот краткий, но неполный обзор:
Math::String treat string sequences like numbers
Math::FixedPrecision calculate with a fixed precision
Math::Currency for currency calculations
Bit::Vector manipulate bit vectors fast (uses C)
Math::BigIntFast Bit::Vector wrapper for big numbers
Math::Pari provides access to the Pari C library
Math::Cephes uses the external Cephes C library (no
big numbers)
Math::Cephes::Fraction fractions via the Cephes library
Math::GMP another one using an external C library
Math::GMPz an alternative interface to libgmp's big ints
Math::GMPq an interface to libgmp's fraction numbers
Math::GMPf an interface to libgmp's floating point numbers Выбирайте с умом.
© 1993–2021 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.36.0/perlop