Как сохранить захват регулярных выражений в массиве в Perl?
Я пытаюсь использовать регулярное выражение в Perl. Мне было интересно, можно ли сохранить все совпадения с выражением в массив? Я знаю, что могу использовать следующее: ($1,...,$n) = m/expr/g;
, но кажется, что это можно использовать, только если вы знаете количество совпадений, которое вы ищете. Я пробовал my @array = m/expr/g;
, но это не работает.
Спасибо за вашу помощь!
Ответы
Ответ 1
Если вы выполняете глобальное соответствие (/g
), то контекст в регулярном выражении возвращает список всех захваченных совпадений. Просто выполните:
my @matches = ( $str =~ /pa(tt)ern/g )
Эта команда, например:
perl -le '@m = ( "foo12gfd2bgbg654" =~ /(\d+)/g ); print for @m'
Выдает вывод:
12
2
654
Ответ 2
См. руководство пользователя perldoc perlop в разделе "Согласование в контексте списка":
Если параметр /g не используется, m//в контексте списка возвращает список, состоящий из подвыражения, согласованные скобками в шаблоне, то есть ($ 1, $2, $3...)
Модификатор/g определяет глобальное сопоставление шаблонов, то есть совпадение столько раз, сколько возможно внутри строки. Как он себя ведет, зависит от контекста. В контексте списка это возвращает список подстрок, соответствующих любым скобкам в регулярном выражении. Если круглых скобок нет, он возвращает список всех совпадающих строк, как если бы вокруг всего шаблона были круглые скобки.
Вы можете просто захватить все совпадения, назначив массив или иначе выполнив оценку в контексте списка:
my @matches = ($string =~ m/word/g);
Ответ 3
Иногда вам нужно получить все совпадения по всему миру, как это делает PHP preg_match_all
. Если это ваш случай, то вы можете написать что-то вроде:
# a dummy example
my $subject = 'Philip Fry Bender Rodriguez Turanga Leela';
my @matches;
push @matches, [$1, $2] while $subject =~ /(\w+) (\w+)/g;
use Data::Dumper;
print Dumper(\@matches);
Он печатает
$VAR1 = [
[
'Philip',
'Fry'
],
[
'Bender',
'Rodriguez'
],
[
'Turanga',
'Leela'
]
];
Ответ 4
Я думаю, что это объяснительный пример. Обратите внимание, что модификатор /g
в первом регулярном выражении:
$string = "one two three four";
@res = $string =~ m/(\w+)/g;
print Dumper(@res); # @res = ("one", "two", "three", "four")
@res = $string =~ m/(\w+) (\w+)/;
print Dumper(@res); # @res = ("one", "two")
Помните, что вам нужно убедиться, что значение lvalue находится в контексте списка, что означает, что вы должны окружать скалярные значения скобками:
($one, $two) = $string =~ m/(\w+) (\w+)/;
Ответ 5
Обратите внимание, что если вы знаете количество групп захвата, которое вам нужно на одно совпадение, вы можете использовать этот простой подход, который я представляю в качестве примера (из 2 групп захвата).
Предположим, у вас есть некоторые данные
my $mess = <<'IS_YOURS';
Richard Rich
April May
Harmony Ha\rm
Winter Win
Faith Hope
William Will
Aurora Dawn
Joy
IS_YOURS
Со следующим регулярным выражением
my $oven = qr'^(\w+)\h+(\w+)$'ma; # skip the /a modifier if using perl < 5.14
Я могу захватить все 12 (6 пар, а не 8... Гармония сбежала и Джой отсутствует) в @box
ниже.
my @box = $mess =~ m[$oven]g;
Если я хочу "разобрать" детали коробки, я мог бы просто сделать:
my %hash = @box;
Или я просто мог полностью пропустить коробку,
my %hash = $mess =~ m[$oven]g;
Обратите внимание, что %hash
содержит следующее. Порядок утерян, и дублирующие ключи (если таковые существовали) сдавлены:
(
'April' => 'May',
'Richard' => 'Rich',
'Winter' => 'Win',
'William' => 'Will',
'Faith' => 'Hope',
'Aurora' => 'Dawn'
);