При регулярных выражениях, когда вы думаете: «Я хочу последнее из», вы должны немедленно думать о шаблоне .*
, потому что жадность регулярных выражений делает именно то, что вы хотите.
Например, /^(.*)a(.*)$/
соответствует "abababab"
в
ababab
в $1
a
соответствует литералу в шаблоне
b
в $2
Давайте подумаем над процессом матча. Представьте .*
как Августа Глупа .
Август: Ausgezeichnet! Якорь ^
означает, что я начинаю с самого начала. Оттуда я буду есть все конфеты!
Вилли Вонка: Но, мой дорогой Август, ты должен поделиться с другими детьми.
Август: Хорошо, я получаю "abababa"
, а они получают "b"
. Счастливы?
Вилли Вонка: Но следующий ребенок в очереди не любит b
конфеты.
Август: Тогда я оставлю "ababab"
для себя и оставлю "ab"
для остальных.
В этот момент у Августа большая кучка, скромный маленький Чарли Бакет получает свой сингл a
, а Верука Солт - хотя и хмурится из-за скудного количества - теперь получает хоть что-то.
Другими словами, $2
содержит все после последнего a
. Чтобы быть привередливыми, якоря ^
и $
являются избыточными, но мне нравится сохранять их для дополнительного акцента.
Приведя это в действие, вы могли бы написать
#! /usr/bin/env perl
use strict;
use warnings;
sub last_fields {
local($_) = @_;
my @last;
push @last, $1 =~ /^.*\|(.+)$/ ? $1 : undef
while /\[(.*?)\]/g;
wantarray ? @last : \@last;
}
Внешний while
разбивает строку на [...]
кусков и предполагает, что правая квадратная скобка не может встречаться внутри блока. В каждом блоке мы используем /^.*\|(.+)$/
для захвата в $1
всего, что находится после последней трубы.
Тестирование на вашем примере выглядит как
my $s = "[0|0|{A=145,B=2,C=12,D=18}|!]" .
"[0|0|{A=167,B=2,C=67,D=17}|.1iit]" .
"[196|0|{A=244,B=6,C=67,D=12}|10:48AM]" .
"[204|0|{A=9,B=201,C=61,D=11}|Calculator]" .
"[66|0|{A=145,B=450,C=49,D=14}|Coffee]";
use Test::More tests => 6;
my @lasts = last_fields $s;
# yes, is_deeply could do this in a single call,
# but it's laid out explicitly here for expository benefit
is $lasts[0], "!";
is $lasts[1], ".1iit";
is $lasts[2], "10:48AM";
is $lasts[3], "Calculator";
is $lasts[4], "Coffee";
is scalar @lasts, 5;
Все тесты пройдены:
$ ./match-last-of
1..6
ok 1
ok 2
ok 3
ok 4
ok 5
ok 6
Вывод prove
приятнее. Запустите его сами, чтобы увидеть цветовую кодировку.
$ prove ./match-last-of
./match-last-of .. ok
All tests successful.
Files=1, Tests=6, 0 wallclock secs ( 0.02 usr 0.01 sys + 0.02 cusr 0.00 csys = 0.05 CPU)
Result: PASS