Perl регулярное выражение regex

Я хотел бы сопоставить прямую ссылку с регулярным выражением. Шаблон, который я ищу, это

[snake-case prefix]_[snake-case words] [same snake-case prefix]_number

Например:

foo_bar_eighty_twelve foo_bar_8012

Я не могу извлечь foo_bar а также eighty_twelve не глядя сначала на foo_bar_8012, Таким образом, мне нужна прямая ссылка, а не обратная ссылка, которая работает, только если мой префикс не является префиксом в виде змеи.

my $prefix = "foo";
local $_ = "${prefix}_thirty_two = ${prefix}_32";

# Backward reference that works with a prefix with no underscores
{
    /(\w+)_(\w+) \s+ = \s+ \1_(\d+)/ix;
    print "Name: $2 \t Number: $3\n";
}

# Wanted Forward reference that do not work :(
{
    /\2_(\w+) \s+ = \s+ (\w+)_\d+/ix;
    print "Name: $1 \t Number: $2\n";
}

К сожалению, моя прямая ссылка не работает, и я не знаю почему. Я читал, что Perl поддерживает такие шаблоны.

Любая помощь?

2 ответа

Решение

Следующее предположение неверно:

"Я не могу извлечь foo_bar и eightty_twelve, не посмотрев сначала на foo_bar_8012".

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

Ниже показано, как вы могли бы достичь своей цели, используя простые обратные ссылки:

use strict;
use warnings;

while (<DATA>) {
    if (m{\b(\w+)_(\w+)\s+\1_(\d+)\b}) {
        print "Prefix = $1, Name = $2, Number = $3\n";
    } else {
        warn "Not found: $_"
    }
}
__DATA__
foo_thirty_two foo_32
foo_bar_eighty_twelve foo_bar_8012

Выходы:

Prefix = foo, Name = thirty_two, Number = 32
Prefix = foo_bar, Name = eighty_twelve, Number = 8012

AFAIK Форвардные ссылки - это не волшебная пуля, которая позволяет менять группы захвата и ссылки.

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

Я решил проблему с помощью обратных ссылок в сочетании с прогнозом. Вот так:

/(?=.*=\s*([a-z]+))\1_(\w+) \s+ = \s+ \w+_\d+/ix

Это работает, потому что предварительный просмотр инициализирует первую группу захвата перед "фактическим" выражением. Для справки, эта часть является прогнозом:

(?=.*=\s*([a-z]+))

и это в основном просто своего рода "суб-регулярное выражение". Причина, по которой я использую [az]+, заключается в том, что \w+ включает подчеркивание. И я не думаю, что это было то, что вы хотели.

Другие вопросы по тегам