2016-04-04 2 views
3

Я пытался сохранить первую группу в @a1 и вторую группу в @a2Сохраните элемент группировки в двух разных массивах в perl?

my $string = "abc123def456abc321def654"; 
my (@a1,@a2) = $string =~m/abc(\d+)def(\d+)/g; 
$, = "\n"; 
print @a1; 

Результат является , а затем @a2 пуст. Но я хочу, чтобы результат был @a1 = 123 321; @a2 = 456 654 Для этого результата я попробовал хэш, поскольку для хранения ключей первая группировка и значения являются второй группировкой, но проблема в дубликатах удаляется. Любой возможный способ сделать это с помощью одного регулярного выражения?

Я пробовал eval group в пределах соответствующего образца. Я получаю правильный результат от @a1, но @a2 не так. И не знаю, в чем проблема?

my (@a1, @a2); 
$string =~m/abc(\d+) (?{push @a1, $1}) def(\d+)(?{push @a2,$2 }) \G/x; 

@a1 результат

1234 
321 
666 

@a2 результат

4567 
456 
45 
4 
654 
65 
6 
777 
77 
7 
+0

Почему вы пытаетесь принудить это к одному регулярному выражению? – Sobrique

+0

@sorbrique У меня был один звонок, он сказал, что это возможно с одним регулярным выражением. Так что я пытаюсь это долгое время с группой eval, но я не мог получить результат. – mkHun

+0

@mkHun. Поскольку вам кажется, что он строго нуждается во всем внутри регулярного выражения, я добавил это к моему ответу. – zdim

ответ

1

Я нашел ответ на свой вопрос. Я использовал атомную группу и фиксировал результат. Backtracking - проблема моего второго случая, поэтому я использовал атомные группы, чтобы избежать обратного отслеживания.

$string =~m/abc(\d+)(?{push @a1, $1;})def(?>(\d+)) (?{ push @a2,$2; })\G/x; 
1

Это то, что вы после этого;

#!/usr/bin/env perl 
use v5.12; 

my $string = "abc123def456abc321def654"; 
my (@a1, @a2); 
while ($string =~ /abc(\d+)def(\d+)/g) { 
    push @a1, $1; 
    push @a2, $2; 
} 
$, = "\n" ; 
say @a1; 
say @a2; 

# Output 
# 123 
# 321 
# 456 
# 654 

Как правило, старайтесь не предполагать, что совпадения успешны. Вместо того, чтобы напрямую назначать переменные, сначала выполняйте логический тест («если» или «пока») по результату совпадения, а затем выполните назначение.

+0

Я думаю, что этот ответ может извлечь пользу из объяснения того, почему все числа заканчиваются в первом массиве. – Sobrique

+0

Если вы удалите '$, =" \ n "и замените' say @ a1; скажем @ a2' с 'say join (", ", @ a1); скажем, join (",", @ a2); 'вы увидите, что все числа не находятся в первом массиве. – Marty

+0

@Marty Я попробовал группу eval с '\ G', все возможное для этого. – mkHun

2

Вы можете сделать:

use List::Util 'pairs'; 
my @a12 = pairs $string =~ /abc(\d+)def(\d+)/g; 
my @a1 = map $_->[0], @a12; 
my @a2 = map $_->[1], @a12; 

или

use List::MoreUtils 'part'; 
my $i = 0; 
my @part = part { $i++ % 2 } $string =~ /abc(\d+)def(\d+)/g; 
my @a1 = @{ $part[0] }; 
my @a2 = @{ $part[1] }; 

Или просто пропустить настройки @ a1 и a2 @ и использовать данные @ a12 или @part.

1

Обновление   Добавлена ​​версия, которая делает все это в регулярном выражении на основе пояснений по требованию.


Построить хэш: Ключ шаблон (abc, def и т.д.), значение является ссылкой на массив со своими матчами.

my %h; 
() = $string =~ /([a-z]+)(\d+)(?{push @{$h{$1}}, $2;})/g; 

() The необходимо ввести контекст списка, так как в противном случае только первый матч происходит, с /g только делает его прыгать от матча к матчу. См. perlrequick. Обратите внимание, что текущий код в соответствующей части является экспериментальной функцией. Вместо этого вы можете оценить код в замещающей части.

my %h; 
$string =~ s/([a-z]+)(\d+)/{push @{$h{$1}}, $2}/eg; 

Это, конечно, разрушительно для оригинальной струны.

В результате хеш имеет ключи, которые являются шаблонами (abc, def, ...), при этом значениями ключей являются массив-ref со всеми совпадениями для этого ключа. У вас может быть любое количество пар цифр, а не только два. Смотри ниже.

Оба этих варианта печатаются так же, как показано ниже.


первоначально

Опубликовано Это предполагает шаблон (ваш abc или def), а затем при помощи цифр. Здесь используется шаблон [a-zA-Z], в соответствии с вашими примерами. У вас может быть любое количество таких пар, а не только два.

use warnings; 
use strict; 

my $string = "abc123def456abc321def654"; 

my %h; 
my $patt = qr/[a-zA-Z]/; # for example 

push @{$h{$1}}, $2 while ($string =~ /($patt+)(\d+)/g); 

print "$_ => @{$h{$_}}\n" for keys %h; 

Печать

 
def => 456 654 
abc => 123 321 

С более двух пар шаблонов цифр (добавленных ghi111 и ghi222),

my $string = "abc123def456abc321ghi111def654ghi222"; 
# exactly the same code ... 

Печать

 
def => 456 654 
abc => 123 321 
ghi => 111 222 

+0

Благодарим вас за полезный ответ. Я узнаю от вас новые вещи. Но я нашел ответ на свой вопрос с атомной группой. :) – mkHun

+0

Я понятия не имею, что такое -1. Код запускается и печатается, как показано. – zdim