Соответствие n круглых скобок в регулярном выражении Perl - PullRequest
0 голосов
/ 18 июня 2010

У меня есть некоторые данные, которые я анализирую в Perl, и в ближайшем будущем я буду добавлять все больше и больше форматированных данных. Я хотел бы написать простую в использовании функцию, в которую я мог бы передать строку и регулярное выражение, и она возвращала бы все, что в скобках. Это будет работать примерно так (псевдокод):

sub parse {
  $data = shift;
  $regex = shift;

  $data =~ eval ("m/$regex/")
  foreach $x ($1...$n)
  {
    push (@ra, $x); 
  }
  return \@ra;
}

Тогда я мог бы назвать это так:

@subs = parse ($data, '^"([0-9]+)",([^:]*):(\W+):([A-Z]{3}[0-9]{5}),ID=([0-9]+)');

Как видите, у этого кода есть пара проблем. Я не знаю, сработает ли eval, «foreach» определенно не сработает, и, не зная, сколько круглых скобок, я не знаю, сколько раз выполнить цикл.

Это слишком сложно для разделения, поэтому, если есть какая-то другая функция или возможность, которую я пропускаю, дайте мне знать.

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

Ответы [ 4 ]

6 голосов
/ 18 июня 2010

В контексте списка регулярное выражение возвращает список всех совпадений в скобках.

Итак, все, что вам нужно сделать, это:

my @matches = $string =~ /regex (with) (parens)/;

И при условии, что оно совпадает, @matches будет массивом двух групп захвата.

Итак, используя ваше регулярное выражение:

my @subs = $data =~ /^"([0-9]+)",([^:]*):(\W+):([A-Z]{3}[0-9]{5}),ID=([0-9]+)/;

Также, когда у вас длинные регулярные выражения, в Perl есть модификатор x, который идет после закрывающего разделителя регулярных выражений. Модификатор x позволяет поместить пробел и символы новой строки в регулярное выражение для повышения читабельности.

Если вы беспокоитесь о группах захвата, которые могут иметь нулевую длину, вы можете пропустить совпадения через @subs = grep {length} @subs, чтобы отфильтровать их.

1 голос
/ 18 июня 2010

Тогда я мог бы назвать это так:

@subs = parse($data, 
          '^"([0-9]+)",([^:]*):(\W+):([A-Z]{3}[0-9]{5}),ID=([0-9]+)');

Вместо этого назовите это так:

parse($data, 
    qr/^"([0-9]+)",([^:]*):(\W+):([A-Z]{3}[0-9]{5}),ID=([0-9]+)/);

Далее, ваша задача будет упрощенаесли вы можете использовать именованные захваты (т.е. Perl 5.10 и выше).Вот пример:

#!/usr/bin/perl

use strict; use warnings;

my %re = (
    id => '(?<id> [0-9]+ )',
    name => '(?<name> \w+ )',
    value => '(?<value> [0-9]+ )',
);

my @this = (
    '123,one:12',
    '456,two:21',
);

my @that = (
    'one:[12],123',
    'two:[21],456',
);

my $this_re = qr/$re{id}   ,   $re{name}    : $re{value}/x;
my $that_re = qr/$re{name} : \[$re{value}\] , $re{id}   /x;

use YAML;

for my $d ( @this ) {
    print Dump [ parse($d, $this_re) ];
}

for my $d ( @that ) {
    print Dump [ parse($d, $that_re) ];
}

sub parse {
    my ($d, $re) = @_;
    return unless $d =~ $re;
    return my @result = @+{qw(id name value)};
}

Вывод:

---
- 123
- one
- 12
---
- 456
- two
- 21
---
- 123
- one
- 12
---
- 456
- two
- 21
0 голосов
/ 18 июня 2010

Если вы хотите найти текст внутри пар скобок, вы должны использовать Text :: Balanced .

Но это не то, что вы хотите сделать, так что это вам не поможет.

0 голосов
/ 18 июня 2010

Вы пытаетесь разобрать сложное выражение с регулярным выражением - что недостаточно для работы.Напомним, что регулярные выражения не могут анализировать старшие грамматики.Для интуиции любое выражение, которое может быть вложенным, не может быть проанализировано с помощью регулярного выражения.

...