5

基本的に、私がやろうとしているのは、かなり大きな PHP ファイルを検索し、文字列「search_term」を含む PHP コードのブロックを他のコードに置き換えることです。いえ

<?php
//some stuff
?>
<?php
// some more stuff
$str = "search_term";
// yes...
?>
<?php 
// last stuff
?>

なるべき

<?php
//some stuff
?>
HELLO
<?php 
// last stuff
?>

私がこれまでに持っているのは

$string =~ s/<\?php(.*?)search_term(.*?)\?>/HELLO/ims;

これは、最も近い終了部分に正しく一致しますが、文字列に最も近いものではなく、?>最初の部分から一致を開始します。<?phpsearch_term

私は何を間違っていますか?

4

5 に答える 5

5

通常、貪欲ではないマッチングを使用するのは好きではありません。通常、このような問題が発生するからです。Perl はファイルを見て、最初の を見つけ'<?php'、それから残りの正規表現を探し始めます。'?>'1 番目と 2 番目'<?php'は に一致するため、を通過し、次にと 次の.*を見つけて終了します。search_term'?>'

非貪欲なマッチングとは、実際に必要以上のものに一致する正規表現があり、どの一致を返すかを決定するのは perl に任されていることを意味します。一致させたいものと正確に一致する正規表現を使用することをお勧めします。((?!\?>).)*この場合、代わりに.*?((?!\?>)は否定的な先読みアサーションです)を使用して、必要なものを取得できます。

s/<\?php((?!\?>).)*search_term((?!\?>).)*\?>/HELLO/is;

複数の一致が予想される場合/isgは、 ではなく/is.

または、ファイルをブロックに分割します。

@blocks = split /(\?>)/, $string;
while (@blocks) {
    $block = shift @blocks;
    $sep = shift @blocks;
    if ($block=~/search_term/) {
        print "HELLO";
    } else {
        print $block, $sep;
    }
}
于 2012-05-11T22:34:29.420 に答える
2

最初のキャプチャ グループを置換に戻すだけです。このようなもの:

s/<\?php(.*)<\?php(.*?)search_term(.*?)\?>/<\?php$1HELLO/ims
于 2012-05-11T21:57:35.200 に答える
2
$string =~ s/<\?php(?:(?!\?>|search_term).)*search_term.*?\?>/HELLO/isg;

(?:(?!\?>|search_term).)*文字がorの先頭でないことを確認した、一度に 1 文字ずつ一致します。それが一致を停止すると、文字列内の次のものが である場合、それ以降のすべてが次の まで消費されます。それ以外の場合、その試行は失敗し、次の からやり直します。?>search_termsearch_term?><?php

重要な点は、@RobertYoung のソリューションのように、?>検索時に一致できないことですsearch_termsearch_termどちらにも一致しないことで、後戻りがなくなり、検索がより効率的になります。ソース文字列のサイズによっては問題にならない場合もありますが、パフォーマンスが著しく低下することもありません。

@Benjのソリューション(現在投稿されている)は機能しません。指定したサンプル文字列で目的の出力が得られますが、それは偶然です。最後のコードブロックのみを置き換え、search_term(@mobがコメントしたように)最初のコードブロックの内容を完全に無視します。

于 2012-05-11T23:22:11.303 に答える
1
s/(.*)<\?php.*?search_term.*?\?>/${1}HELLO/ims;

正規表現では、正規表現エンジンは、ターゲット表現に一致する部分文字列の最初の出現を見つけようとしており、最初<?phpと 2 番目の間でそれを見つけ?>ます。

正規表現の先頭に置くこと(.*)で、正規表現エンジンをだまして文字列の最後に移動させ (文字.*列全体に一致するため)、文字列 " " を見つけることができる場所にバックトラックします<?php。そうすれば、結果の一致に<?php必要以上のトークンが含まれなくなります。

于 2012-05-11T22:20:05.073 に答える
0

貪欲でけちなマッチングを使用していますが、それでも一致しすぎる可能性があります。

の一致する繰り返しperlretut、それをよく表しています。

否定一致を使用して支援することもありますが、役に立たないと思います。例えば:

s/^[^A]*A/A/

私の文字が一致していないことを確認します。

しかし、私は通常、複数の行をまたがろうとしているわけではなく、必要がない限り perl を使用していません。

于 2012-05-11T21:58:25.323 に答える