Подтвердить что ты не робот

Как сохранить захват регулярных выражений в массиве в Perl?

Я пытаюсь использовать регулярное выражение в Perl. Мне было интересно, можно ли сохранить все совпадения с выражением в массив? Я знаю, что могу использовать следующее: ($1,...,$n) = m/expr/g;, но кажется, что это можно использовать, только если вы знаете количество совпадений, которое вы ищете. Я пробовал my @array = m/expr/g;, но это не работает.

Спасибо за вашу помощь!

4b9b3361

Ответ 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'
);