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+ включает подчеркивание. И я не думаю, что это было то, что вы хотели.