0

正規表現が変数に保持されている場合、正規表現のテキスト置換について説明できる人はいますか? いくつかのテキスト、Clearcase 構成仕様を実際に処理し、テキストを置き換えようとしています。置換のルールは、一致する正規表現と置換するテキストを持つハッシュの配列に保持されます。

入力テキストは次のようになります。

element  /my_elem/releases/...  VERSION_STRING.020 -nocheckout

ほとんどの置換は、特定のテキスト文字列を含む行を削除するだけであり、これはうまく機能します。場合によっては、テキストを置き換えたいのですが、VERSION_STRING テキストを再利用します。置換式で $1 を使用しようとしましたが、うまくいきません。$1 はマッチでバージョン文字列を取得しますが、$1 の置換は置換で機能しません。

これらの場合、出力は次のようになります。

element  -directory  /my_elem/releases/... VERSION_STRING.020 -nocheckout
element  /my_elem/releases/.../*.[ch]  VERSION_STRING.020 -nocheckout

すなわち。1 行の入力が 2 つの出力になり、バージョン文字列が再利用されました。

コードは次のようになります。最初に正規表現と置換:

my @Special_Regex = (   
                  { regex => "\\s*element\\s*\/my_elem_removed\\s*\/main\/\\d+\$",                  subs => "# Line removed" },
                  { regex => "\\s*element\\s*\/my_elem_changed\/releases\/\.\.\.\\s*\(\.\*\$\)", 
                    subs => "element  \-directory  \/my_elem\/releases\/\.\.\. \\1\nelement  \/my_elem\/releases\/\.\.\.\/\*\.\[ch\]  \\1" }

                );

2 番目の正規表現では、変数 $1 が部分 (.*\$) で定義されており、これは正しく機能しています。ただし、subs 式はそれを置き換えません。

 foreach my $line (<INFILE>)
        {
        chomp($line);
        my $test = $line;
        foreach my $hash (@Special_Regex)
        {
            my $regex = qr/$hash->{regex}/is;
            if($test =~ s/$regex/$hash->{subs}/)
                {
                print "$test\n";
                print "$line\n";
                print "$1\n";
                }
         }
}

私は何が欠けていますか?前もって感謝します。

4

2 に答える 2

3

正規表現の置換文字列は一度だけ評価さ$hash->{subs}れ、その文字列に変換されます。内部変数を補間するには、再度評価する必要があります。修飾子を正規表現の最後に追加して、 Perl に2 番目の補間を実行できるe置換を実行するように指示できます。eval複数のフラグを適用して、複数e回評価することができます (必要な問題がある場合)。tchristが有益に指摘しているように、この場合、ee最初の eval は変数を展開するだけなので、2 番目の eval は展開で変数を展開するために必要です。

詳細perlopについては、sオペレーターについてを参照してください。

于 2010-11-03T17:36:58.637 に答える
2

置換式のコンパイルはありません。したがって、実行できる唯一のことは、eフラグを使用して実行または評価することです。

if($test =~ s/$regex/eval qq["$hash->{subs}"]/e ) { #...

置換文字列に変更\\1した後、私のために働きました。\$1

s/$regex/$hash->{subs}/

一致した部分のみを、完全な置換として格納されているリテラル値に置き換えます。置換を機能させるには、Perl に文字列を文字列として評価させる必要があります。つまり、探している補間動作を得るために、二重引用符を元に戻す必要があることを意味します (それらは一部ではないため)。文字列の。)$hash->{subs}

しかし、それはちょっと不器用なので、replace 式をサブルーチンに変更しました。

my @Special_Regex 
    = ( 
        { regex => qr{\s*element\s+/my_elem_removed\s*/main/\d+$}
        , subs  => sub { '#Line removed' }
        }
    ,   { regex => qr{\s*element\s+/my_elem_changed/releases/\.\.\.\s*(.*$)}
        , subs  => sub { 
            return "element  -directory  /my_elem/releases/... $1\n"
                 . "element  /my_elem/releases/.../*.[ch]  $1"
                 ; 
          }
        }

    );

置換式でエスケープする必要のない多くのものを取り除きました。やりたいことは の値を$1置換文字列に補間することなので、サブルーチンは単純にそれを行います。$1他の何かが一致するまで表示されるため、このコードを実行すると正しい値になります。

したがって、置換は次のようになります。

s/$regex/$hash->{subs}->()/e

もちろん、グローバルに依存していないため、パス $1を作成すると、もう少し防弾になります$1

s/$regex/$hash->{subs}->( $1 )/e

もちろん、次のようにサブを変更します。

subs => sub {
    my $c1 = shift;
    return "element  -directory  /my_elem/releases/... $c1\n"
         . "element  /my_elem/releases/.../*.[ch]  $c1"
         ; 
}

最後に 1 つだけ注意"\.\.\."してください。'...'任意の 3 文字に一致する正規表現で終了しました。

于 2010-11-03T17:39:21.640 に答える