Выпуск 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 →
