web-dev-qa-db-ja.com

正規表現置換のカウンター変数のようなものはありますか?

たとえば、複数行モードなどで多くの一致があり、それらを一致の一部とインクリメントするカウンター番号で置き換える場合。

正規表現のフレーバーにそのような変数があるかどうか疑問に思っていました。見つけられませんでしたが、そのようなものがあることを覚えているようです...

コールバックを置き換えに使用できるスクリプト言語については話していません。これは、RegexBuddy、崇高なテキスト、gskinner.com/RegExrなどのツールでこれを実行できるようにすることです。\ 1または$ 1を使用して、キャプチャされた部分文字列を参照するのと同じように操作できます。

30
user1115652

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配列ソリューションの内挿コード

これに対して:

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!

RHSではなくLHSのコードを使用したソリューション

これにより、増分がマッチ自体に配置されます。

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!

境界を探索する

複数の所有格で機能するWord境界へのより強力なアプローチがあります(以前のアプローチでは機能しません)が、あなたの謎は++$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]?

Unicodeが心配

1960年代スタイルASCIIは約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についての派手な正規表現、しかし、あなたが尋ねてうれしいですか? ☺

58
tchrist