Как сохранить захваты из регулярного выражения Perl в отдельные переменные?
У меня есть регулярное выражение:
/abc(def)ghi(jkl)mno(pqr)/igs
Как бы я мог отображать результаты каждой круглой скобки в 3 разных переменных, по одной для каждой круглой скобки? Сейчас я использую один массив для захвата всех результатов, они выходят последовательно, но затем я должен их разобрать, и список может быть огромным.
@results = ($string =~ /abc(def)ghi(jkl)mno(pqr)/igs);
Ответы
Ответ 1
Ваш вопрос немного двусмыслен для меня, но я думаю, вы хотите сделать что-то вроде этого:
my (@first, @second, @third);
while( my ($first, $second, $third) = $string =~ /abc(def)ghi(jkl)mno(pqr)/igs) {
push @first, $first;
push @second, $second;
push @third, $third;
}
Ответ 2
Начиная с 5.10 вы также можете использовать с именем capture buffers:
#!/usr/bin/perl
use strict; use warnings;
my %data;
my $s = 'abcdefghijklmnopqr';
if ($s =~ /abc (?<first>def) ghi (?<second>jkl) mno (?<third>pqr)/x ) {
push @{ $data{$_} }, $+{$_} for keys %+;
}
use Data::Dumper;
print Dumper \%data;
Вывод:
$VAR1 = {
'first' => [
'def'
],
'second' => [
'jkl'
],
'third' => [
'pqr'
]
};
Для более ранних версий вы можете использовать следующее, которое позволяет не добавлять строку для каждого захваченного буфера:
#!/usr/bin/perl
use strict; use warnings;
my $s = 'abcdefghijklmnopqr';
my @arrays = \ my(@first, @second, @third);
if (my @captured = $s =~ /abc (def) ghi (jkl) mno (pqr) /x ) {
push @{ $arrays[$_] }, $captured[$_] for 0 .. $#arrays;
}
use Data::Dumper;
print Dumper @arrays;
Вывод:
$VAR1 = [
'def'
];
$VAR2 = [
'jkl'
];
$VAR3 = [
'pqr'
];
Но мне нравится хранить связанные данные в единой структуре данных, поэтому лучше вернуться к использованию хэша. Однако это требует вспомогательного массива:
my %data;
my @keys = qw( first second third );
if (my @captured = $s =~ /abc (def) ghi (jkl) mno (pqr) /x ) {
push @{ $data{$keys[$_]} }, $captured[$_] for 0 .. $#keys;
}
Или, если имена переменных действительно являются first
, second
и т.д., или если имена буферов не имеют значения, а только порядок, вы можете использовать:
my @data;
if ( my @captured = $s =~ /abc (def) ghi (jkl) mno (pqr) /x ) {
push @{ $data[$_] }, $captured[$_] for 0 .. $#captured;
}
Ответ 3
Альтернативный способ сделать это будет выглядеть как ответ ghostdog74, но с использованием массива, который хранит хеш-ссылки:
my @results;
while( $string =~ /abc(def)ghi(jkl)mno(pqr)/igs) {
my ($key1, $key2, $key3) = ($1, $2, $3);
push @results, {
key1 => $key1,
key2 => $key2,
key3 => $key3,
};
}
# do something with it
foreach my $result (@results) {
print "$result->{key1}, $result->{key2}, $result->{key3}\n";
}
причем основное преимущество здесь заключается в использовании единой структуры данных, и имеет хороший читаемый цикл.
Ответ 4
@OP, когда скобки скопированы, вы можете использовать переменные $1, $2.... это обратные ссылки
$string="zzzabcdefghijklmnopqrsssszzzabcdefghijklmnopqrssss";
while ($string =~ /abc(def)ghi(jkl)mno(pqr)/isg) {
print "$1 $2 $3\n";
}
Выход
$ perl perl.pl
def jkl pqr
def jkl pqr
Ответ 5
У вас может быть три разных регулярных выражения, каждый из которых фокусируется на определенных группах. Очевидно, вы хотели бы просто назначить разные группы для разных массивов в регулярном выражении, но я думаю, что ваш единственный вариант - разделить регулярное выражение вверх.