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

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

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

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

2 ответа

FMTEYEWTK о необычных регулярных выражениях

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

Простое решение ///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's 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]?

Беспокоясь о Юникоде

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 есть причудливые регулярные выражения, но разве вы не рады, что спросили? ☺

Насколько мне известно, в простых регулярных выражениях их нет.

С другой стороны, есть несколько инструментов, которые предлагают его как расширение , например, grepWin . В справке инструмента (нажмите F1):

Внутри он использует механизм регулярных выражений Perl от Boost, но ${count}реализован внутри (как и в других расширениях).

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