Есть что-то вроде переменной счетчика в регулярном выражении?

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

Мне было интересно, имеет ли какой-либо аромат регулярного выражения такую ​​переменную. Я не мог найти его, но, похоже, я помню, что подобное существует...

Я не говорю о языках сценариев, в которых вы можете использовать обратные вызовы для замены. Это о возможности сделать это в таких инструментах, как RegexBuddy, возвышенный текст, gskinner.com/RegExr,... так же, как вы можете ссылаться на захваченные подстроки с \1 или $1.

Ответ 1

FMTEYEWTK о Fancy Regexes

Хорошо, я собираюсь перейти от простого к возвышенному. Наслаждайтесь!

Простой s///e Решение

Учитывая это:

#!/usr/bin/perl

$_ = <<"End_of_G&S";
    This particularly rapid,
        unintelligible patter
    isn't generally heard,
        and if it is it doesn't matter!
End_of_G&S

my $count = 0;

Затем это:

s{
    \b ( [\w']+ ) \b
}{
    sprintf "(%s)[%d]", $1, ++$count;
}gsex;

производит это

(This)[1] (particularly)[2] (rapid)[3],
    (unintelligible)[4] (patter)[5]
(isn't)[6] (generally)[7] (heard)[8], 
    (and)[9] (if)[10] (it)[11] (is)[12] (it)[13] (doesn't)[14] (matter)[15]!

Интерполированный код в решении Anon Array

В то время как это:

s/\b([\w']+)\b/#@{[++$count]}=$1/g;

производит следующее:

#1=This #2=particularly #3=rapid,
    #4=unintelligible #5=patter
#6=isn't #7=generally #8=heard, 
    #9=and #10=if #11=it #12=is #13=it #14=doesn't #15=matter!

Решение с кодом в LHS вместо RHS

Это добавляет инкремент в пределах самого совпадения:

s/ \b ( [\w']+ ) \b (?{ $count++ }) /#$count=$1/gx;

дает следующее:

#1=This #2=particularly #3=rapid,
    #4=unintelligible #5=patter
#6=isn't #7=generally #8=heard, 
    #9=and #10=if #11=it #12=is #13=it #14=doesn't #15=matter!

Решение решения заикания заикания Решение

Это

s{ \b ( [\w'] + ) \b             }
 { join " " => ($1) x ++$count   }gsex;

генерирует этот восхитительный ответ:

This particularly particularly rapid rapid rapid,
    unintelligible unintelligible unintelligible unintelligible patter patter patter patter patter
isn't isn't isn't isn't isn't isn't generally generally generally generally generally generally generally heard heard heard heard heard heard heard heard, 
    and and and and and and and and and if if if if if if if if if if it it it it it it it it it it it is is is is is is is is is is is is it it it it it it it it it it it it it doesn't doesn't doesn't doesn't doesn't doesn't doesn't doesn't doesn't doesn't doesn't doesn't doesn't doesn't matter matter matter matter matter matter matter matter matter matter matter matter matter matter matter!

Изучение границ

Есть более надежные подходы к границам слов, которые работают для множественных притяжателей (предыдущие подходы не используются), но я подозреваю, что ваша тайна заключается в том, чтобы стрелять ++$count, а не с тонкостями поведения \b.

Я действительно хочу, чтобы люди поняли, что \b не то, что они считают. Они всегда думают, что это означает, что пустое пространство или край строки там. Они никогда не думают об этом как о переходах \w\W или \w\W.

# same as using a \b before:
(?(?=\w) (?<!\w)  | (?<!\W) )

# same as using a \b after:
(?(?<=\w) (?!\w)  | (?!\W)  )

Как вы видите, это условно зависит от того, к чему это прикасается. Вот что такое предложение (?(COND)THEN|ELSE).

Это становится проблемой с такими вещами, как:

$_ = qq('Tis Paul parents' summer-house, isn't it?\n);
my $count = 0;

s{
    (?(?=[\-\w']) (?<![\-\w'])  | (?<![^\-\w']) )
    ( [\-\w'] + )
    (?(?<=[\-\w']) (?![\-\w'])  | (?![^\-\w'])  )
}{
    sprintf "(%s)[%d]", $1, ++$count
}gsex;

print;

который правильно печатает

('Tis)[1] (Paul's)[2] (parents')[3] (summer-house)[4], (isn't)[5] (it)[6]?

Беспокойство о Unicode

Стиль ASCII 1960-х годов устарел примерно на 50 лет. Точно так же, как всякий раз, когда вы видите, что кто-то пишет [a-z], он почти всегда ошибается, оказывается, что такие вещи, как тире и кавычки, не должны отображаться как литералы в шаблонах. В то время как вы были на нем, вы, вероятно, не хотите использовать \w, потому что это также номера и символы подчеркивания, а не только алфавиты.

Представьте эту строку:

$_ = qq(\x{2019}Tis Ren\x{E9}e\x{2019}s great\x{2010}grandparents\x{2019} summer\x{2010}house, isn\x{2019}t it?\n);

который вы могли бы иметь как литерал с помощью use utf8:

use utf8;
$_ = qq(’Tis Renée’s great‐grandparents’ summer‐house, isn’t it?\n);

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

#!/usr/bin/perl -l
use 5.10.0;
use utf8;
use open qw< :std :utf8 >;
use strict;
use warnings qw< FATAL all >;
use autodie;

$_ = q(’Tis Renée’s great‐grandparents’ summer‐house, isn’t it?);

my $count = 0;

s{ (?<WORD> (?&full_word)  )

   # the rest is just definition
   (?(DEFINE)

     (?<word_char>   [\p{Alphabetic}\p{Quotation_Mark}] )

     (?<full_word>

             # next line won't compile cause
             # fears variable-width lookbehind
             ####  (?<! (?&word_char) )   )
             # so must inline it

         (?<! [\p{Alphabetic}\p{Quotation_Mark}] )

         (?&word_char)
         (?:
             \p{Dash}
           | (?&word_char)
         ) *

         (?!  (?&word_char) )
     )

   )   # end DEFINE declaration block

}{
    sprintf "(%s)[%d]", $+{WORD}, ++$count;
}gsex;

print;

Этот код при запуске создает следующее:

(’Tis)[1] (Renée’s)[2] (great‐grandparents’)[3] (summer‐house)[4], (isn’t)[5] (it)[6]?

Хорошо, так что, возможно, было FMTEYEWTK о причудливых регулярных выражениях, но arent вы рады, что спросили? ☺