12

次のようなテキストがあります。

hello world /* select a from table_b
*/ some other text with new line cha
racter and there are some blocks of 
/* any string */ select this part on
ly 
////RESULT rest string

テキストは複数行あり、最後に出現した "*/" から "////RESULT" まで抽出する必要があります。この場合、結果は次のようになります。

 select this part on
ly 

perlでこれを達成する方法は?

私は試み\\\*/(.|\n)*////RESULTましたが、それは最初の「* /」から始まります

4

3 に答える 3

20

このような場合に役立つトリックは、正規表現の前に貪欲なパターンを付けることです.*。これにより、残りのパターンが一致する前に、できるだけ多くの文字を一致させようとします。それで:

my ($match) = ($string =~ m!^.*\*/(.*?)////RESULT!s);

このパターンをコンポーネントに分割してみましょう。

  • ^.*文字列の先頭から始まり、できるだけ多くの文字に一致します。(s修飾子を使用.すると、改行も一致させることができます。)文字列の先頭アンカー^は厳密には必要ありませんが、一致が失敗した場合にregexpエンジンがバックトラックに多くの時間を浪費しないようにします。

  • \*/リテラル文字列と一致します*/

  • (.*?)任意の数の文字に一致してキャプチャします。これ?により、貪欲にならないため、正規表現の残りの部分が一致する可能性のある位置が複数ある場合に備えて、できるだけ少ない文字を一致させることをお勧めします。

  • 最後に、////RESULTそれ自体に一致します。

パターンにはスラッシュがたくさん含まれており、傾いた楊症候群を避けたかったので、代替の正規表現区切り文字を使用することにしました。感嘆符(!)は、通常の正規表現構文と衝突しないため、一般的な選択肢です。


編集:以下の池上との議論によると、この正規表現をより長い正規表現のサブパターンとして使用したい場合、および一致する文字列(.*?)決して含まれないことを保証したい場合////RESULTは、次のように、正規表現のこれらの部分を独立した(?>)部分式でラップします。

my $regexp = qr!\*/(?>(.*?)////RESULT)!s;
...
my $match = ($string =~ /^.*$regexp$some_other_regexp/s);

これにより、正規表現の残りの部分が一致しないことを意味する場合でも(?>)、次善の一致(つまり、最初の部分文字列の一致を超えて拡張するもの)を受け入れるのではなく、その中のパターンが失敗します。////RESULT

于 2013-01-02T19:00:13.427 に答える
5
(?:(?!STRING).)*

を含まない任意の数の文字に一致しますSTRING。に似[^a]ていますが、文字ではなく文字列用です。

特定の入力が発生しないことがわかっている場合はショートカットを使用できますが (Kenosis や Ilmari Karonen が行ったように)、指定したものと一致するのは次のとおりです。

my ($segment) = $string =~ m{
    \*/
    ( (?: (?! \*/ ). )* )
    ////RESULT
    (?: (?! \*/ ). )*
    \z
}xs;

*/の後に が表示されても気にしない場合////RESULTは、次の方法が最も安全です。

my ($segment) = $string =~ m{
    \*/
    ( (?: (?! \*/ ). )* )
    ////RESULT
}xs;

最後////RESULT*/. 上記は最後のものまで一致します。最初のものまで一致させたい場合は、

my ($segment) = $string =~ m{
    \*/
    ( (?: (?! \*/ | ////RESULT ). )* )
    ////RESULT
}xs;
于 2013-01-02T18:57:52.113 に答える
4

1 つのオプションを次に示します。

use strict;
use warnings;

my $string = <<'END';
hello world /* select a from table_b
*/ some other text with new line cha
racter and there are some blocks of 
/* any string */ select this part on
ly 
////RESULT
END

my ($segment) = $string =~ m!\*/([^/]+)////RESULT$!s;

print $segment;

出力:

 select this part on
ly 
于 2013-01-02T18:44:05.670 に答える