6

すべての正規表現一致変数をクリア/リセットするための最良の方法は何ですか?

  • $1正規表現操作間でリセットされず、最新の一致を使用する方法の例:

    $_="this is the man that made the new year rumble"; 
    / (is) /; 
    / (isnt) /; 
    say $1;          # outputs "is"
    
  • ループを操作するときにこれがどのように問題になる可能性があるかの例:

    foreach (...){
       /($some_value)/;
       &doSomething($1) if $1;
    }
    

更新:これを行う必要があるとは思いませんでしたが、例2は単なる例です。この質問は、一致する変数のリセットに関するものであり、それらを実装するための最良の方法ではありません。

とにかく、もともと私のコーディングスタイルは、明示的でif-blocksを使用することでよりインラインでした。これ(例2)に戻った後、コードの多くの行を読む方がはるかに簡潔であるため、この構文を理解するのが速くなります。

4

6 に答える 6

18

グループ変数の状態ではなく、一致からの戻り値を使用する必要があります。

foreach (...) {
    doSomething($1) if /($some_value)/;
}

$ 1などは、一致が成功した場合にのみ最新の一致を反映することが保証されます。試合が成功した直後以外は、それらを見るべきではありません。

于 2012-04-18T20:43:08.947 に答える
14

正規表現キャプチャ*は、一致が成功するとリセットされます。正規表現のキャプチャをリセットするには、一致することが保証されている簡単な一致操作を使用します。

"a" =~ /a/;  # Reset captures to undef.

ええ、それは奇妙に見えますが、あなたは何か奇妙なことをするように頼みました。

コードを修正する場合、奇妙に見える回避策は必要ありません。コードを修正すると、バグが明らかになります。

修正:

$_ = "this is the man that made the new year rumble"; 
if (/ (is) / || / (isnt) /) {
   say $1; 
} else{ 
   ...  # You're currently printing something random.
}

for (...) {
   if (/($some_pattern)/) {
      do_something($1);
   }
}

* —バックリファレンスは、以前にキャプチャされたテキストと一致する正規表現パターンです。例\1\k<foo>。あなたは実際に「正規表現キャプチャバッファ」について話している。

于 2012-04-18T21:54:44.357 に答える
5

試合が成功したかどうかをテストする必要があります。例えば:

foreach (...){
   /($some_value)/ or next;
   doSomething($1) if $1;
}

foreach (...){
   doSomething($1) if /($some_value)/ and $1;
}

foreach (...){
   if (/($some_value)/) {
      doSomething($1) if $1;
   }
}

何であるか$some_value、および空の文字列や0の一致をどのように処理するかによって、テストする必要がある場合とない場合があり$1ます。

于 2012-04-18T20:44:21.613 に答える
2

既存の有用な回答を補完するために(そして、ブールコンテキストで一致する操作の結果を通常テストし、テストが成功した場合にのみアクションを実行するという賢明な推奨事項):

シナリオに応じて、問題へのアプローチを変えることができます。

免責事項:私は経験豊富なPerlプログラマーではありません。このアプローチに問題がある場合はお知らせください。

一致する操作をdo { ... }ブロックスコープで囲み、そのブロックに対するすべての正規表現関連の特殊変数(、、$&... $1)をスコープします。

したがって、を使用しdo { ... }て、これらの特別な変数が最初に設定されないようにすることができます(ただし、ブロック外の以前の正規表現操作からのものは明らかに有効なままです)。例えば:

$_="this is the man that made the new year rumble"; 

# Match in current scope; -> $&, $1, ... *are* set.
/ (is) /;

# Match inside a `do` block; the *new* $&, $1, ... values
# are set only *inside* the block; 
# `&& $1` passes out the block's version of `$1`.
$do1 = do { / (made) / && $1 };

print "\$1 == '$1'; \$do1 == '$do1'\n";  # -> $1 == 'is'; $do1 == 'made'
  • このアプローチの利点は、現在のスコープの特別な正規表現変数が設定または変更されないことです対照的に、受け入れられた回答は、、などの変数を変更$&します$'
  • 欠点は、対象の変数を明示的に渡す必要があることです。ただし、デフォルトではマッチング操作の結果が得られますが、キャプチャバッファの内容のみに関心がある場合は、それで十分です。
于 2015-07-17T18:05:37.940 に答える
1

あなたはそれをこのようにすべきです:

foreach (...) { 
   someFnc($1) if /.../; 
}

しかし、自分のスタイルに固執したい場合は、これをアイデアとして確認してください。

$_ = "this is the man that made the new year rumble";  

$m = /(is)/   ? $1 : undef;
$m = /(isnt)/ ? $1 : undef;

print $m, "\n" if defined $m;
于 2012-04-18T20:55:33.370 に答える
0

キャプチャをリストに割り当てると、希望どおりに動作します。

for ("match", "fail") {
    my ($fake_1) = /(m.+)/;
    doSomething($fake_1) if $fake_1;
}
于 2012-04-18T21:53:07.920 に答える