Выпуск 28. Июнь 2015
← Рефакторинг Legacy | Содержание | Полный список изменений в Perl 5.22.0 →Что нового в Perl 5.22
Краткий обзор наиболее заметных изменений в свежем стабильном релизе перла
Версия 5.22, в отличие от нескольких предыдущих, содержит некоторые интересные новшества, о которых стоит рассказать.
Регулярные выражения
Новый перл поставляется с новым юникодом версии 7.0. Одновременно появилось несколько выражений, которые можно использовать для поиска границ букв, слов и предложений:
\b{gcb}
или\b{g}
— границы букв (точнее, графем: grapheme cluster boundary);\b{wb}
— границы слов (word boundary);\b{sb}
— границы предложений (sentence boundary).
Пробуем делить по графемам (важно не забыть дописать инструкции про utf8).
use v5.22;
use utf8;
use open qw(:std :utf8);
my @str = ('Über', "U\x{308}ber");
for (@str) {
my @ch = split //;
say scalar @ch;
say join ',', @ch;
my @gl = split /\b{g}/;
say scalar @gl;
say join ',', @gl;
}
Ожидаемо, первый split //
делит строку на байты (4 для первой строки и 5 для второй), а второй split /\b{gcb}/
на буквы.
Выражение \b{wb}
совпадает на границе юникодных слов. Причем речь идет не только о составных символах (как на примере Ü выше). Например, слова с апострофом принимаются за слово целиком вместе с апострофом.
my $book = "Perl pour l'impatient";
say for grep /\S/, split /\b{wb}/, $book;
Этот пример напечатает три слова, а если разделить строку по шаблону /\b/
, то пять слов (включая апостроф, выделенный в отдельное слово).
Наконец, выражение \b{sb}
совпадает с границами предложений. Границей предложения могут стать и кавычки с цитатой, и точки после инициалов и даже перевод строки (точнее, все, что совпадает с /\R/
). То есть реальной пользы от \b{sb}
, видимо, не очень много.
my $text = <<TEXT;
Ultimately, it's Larry's choice. I haven't been able to convince Larry, he hasn't been able to convince me, but he has good reasons for the choices that he's made and he's a really smart guy. It might be that having Perl 5 and Perl 6 will actually turn out to be an advantage in some way that most of the rest of the community doesn't realize until we look back and say: “You know what? Larry was right again!”
TEXT
my @s = $text =~ /(.+?) *\b{sb}/g;
say "[$_]" for @s;
Подробные правила, принятые в юникоде для членения текста на значимые части, описаны в документе Unicode Text Segmentation.
/n для запрета захвата
В дополнение к (?:...)
появился модификатор /n
, который действует сразу на все выражение.
#'2015-06-02' =~ /(\d+)-(\d+)-(\d+)/; # захватит
'2015-06-02' =~ /(\d+)-(\d+)-(\d+)/n; # не захватит
say $1;
say $2;
say $3;
use re ‘strict’
В качестве экспериментальной добавлена возможность дополнительной проверки правильности регулярных выражений:
no warnings 'experimental::re_strict';
use re 'strict';
В документации [показан пример](http://search.cpan.org/~rjbs/perl-5.22.0/ext/re/re.pm#‘strict’_mode), когда такая проверка выдает предупреждение:
qr/\xABC/
Без strict-режима все произойдет молча, а при наличии use re 'strict';
появится сообщение:
Use \x{...} for more than two hex characters in regex;
Более явные ошибки, тем не менее, удается отследить и в обычном режиме. Например, попытка использовать несуществующий режим для поиска границ \b{ww}
:
'ww' is an unknown bound type in regex;
Многое, по видимому, упирается в обратную совместимость. Было бы неплохо в будущем включать строгий режим по умолчанию, как минимум вместе с директивой use v5.22;
, как это сейчас происходит c обычным use strict;
при указании, например, use v5.12;
.
Флаги по умолчанию
Инструкция вида use re '/ax'
автоматически подключает все указанные в ней модификаторы ко всем регулярным выражениям до конца текущей области видимости. Соответственно, no re '/ax'
отключает перечисленные флаги.
use re '/i';
my @p = "ABC" =~ /([a-z])/g;
say for @p;
В этой программе к регулярному выражению добавится модификатор /i
, поэтому программа напечатает три строки с прописными буквами.
Обратите внимание, что сразу записать use re '/g'
невозможно:
Unknown regular expression flag "g" at regex-flags.pl line 3.
Впрочем, это невозможно и в записью вида (?i:...)
:
my @p = "ABC" =~ /(?ig:[a-z])/;
Здесь сразу на помощь приходит use re 'strict'
:
Useless (?g) - use /g modifier in regex;
Операторы
Битовые операторы
Экспериментальная фича bitwise
активирует набор операторов |.
, &.
, ^.
, ~.
и, соответственно, |.=
, &.=
, ^.=
, ~.=
, которые выполняют побитовые действия, рассматривая аргументы как строки.
use feature 'bitwise';
no warnings 'experimental::bitwise';
say 400 | 142; # 414
say 400 |. 142; # 542
say 40 | 12; # 44
say 40 |. 12; # 52
В примерах с |
выполняется операция над числами: например, 40|12
это 0x28|0x0С
или 0b00101000|0b00001100
, что дает 0b00101100
= 44
.
С новым оператором побитовые операции происходят посимвольно: ord('4')|ord('1')
= 52|49
= 0b110100|0b110001
= 0b110101
= 53
, то есть символ 5
, а ord('0')|ord('2')
= 48|50
= 0b110000|0b110010
= 0b110010
(символ 2
).
В операторах с точкой наличие или отсутствие пробела после нее решается в пользу более длинного оператора, сравните:
say 40 | .12; # 40
say 40 |. 12; # 52
say 40 |.12; # 52
Аналогично работают и другие операторы.
Строковое побитовое сложение наверное удобно использовать для совмещения двух ASCII-строк, в которых символы из одной встают на пробельные позиции в другой (правда, заодно происходит преобразование в нижний регистр):
say "Hello, !" |. " World"; # hello, world!
С юникодом такие фокусы не имеют смысла:
use utf8;
say "Привет, !" |. " мир"; # пѠивеѢ, миѠ!
Тем не менее, введение новых операторов — вполне в пределах картины мира перла, в которой часть операторов не полиморфна, а разделяется на строковые и числовые (ср. с операторами сравнения). Кстати, изначально предлагалась сделать новые операторы более последовательными, а именно, для строковых операций использовать строковые же названия band
, bor
, bxor
и bnot
.
<<>>
Двойной ромб (double diamond) — более безопасная версия оператора <>
. Отличие проявляется, когда он используется для чтения из файлов, имена которых указаны в командной строке.
Если файлов нет, то чтение происходит из стандартного потока ввода, и никакой разницы нет:
my $str = <>;
say $str;
При чтении из STDIN второй вариант делает то же самое:
my $str = <<>>;
say $str;
Если же при запуске программы в командной строке были указаны аргументы, то оператор-ромб последовательно открывает все файлы и читает из них, причем если аргумент содержит специальные символы типа >
или |
, то они ведут себя так же как в функции open
, вызванной с двумя аргументами:
open my $f, 'ls |';
Следующий пример печатает содержимое текущего каталога:
open my $f, 'ls |';
print while <$f>;
Если такой аргумент передать в командной строке и при этом использоавть традиционный ромб, то происходит ровно то же:
print while <>;
Запуск:
perl diamond3.pl 'ls |'
Двойной ромб в таких случаях открывает файл вариантом функции open
с тремя аргументами, и особой интерпретации таких символов не происходит:
open my $f, '<', 'ls |';
print while <$f>;
Эта программа будет пытаться открыть файл с именем ls |
. Аналогично, чтобы открыть этот файл из командной строки:
perl ddiamond3.pl 'ls |'
достаточно воспользоваться двойным ромбом:
print while <<>>;
Новая многосимвольная форма оператора, судя по всему, потребовалась только для обратной совместимости.
Прочее
Из интересных возможностей, которые здесь не упомянуты, я бы обратил внимание на следующее:
Подробности можно прочитать в переводе perldelta, опубликованном в этом номере журнала.
← Рефакторинг Legacy | Содержание | Полный список изменений в Perl 5.22.0 →