3

次のような新しい行を含む入力がある場合:

[INFO]
xyz
[INFO]

$アンカーを使用してxyzパーツを引き出すにはどうすればよいですか?私はのようなパターンを試しました/^\[INFO\]$(.*?)$\[INFO\]/msが、perlは私に:

Use of uninitialized value $\ in regexp compilation at scripts\t.pl line 6.

アンカーが期待どおりに機能するように補間を停止する方法はありますか?

編集:重要なのは、行末アンカーがドル記号であるということですが、パターン全体に行末アンカーを散在させる必要がある場合があります。パターンが補間している場合は、初期化されていないなどの問題が発生する可能性があります$\。たとえば、ここで受け入れられる解決策はです/^\[INFO\]\s*^(.*?)\s*^\[INFO\]/msが、それは最初の問題の核心を解決しません。アンカーを変更して、^補間が行われないようにしました。この入力を使用して、自由に行うことができます。$しかし、パターンでEOLを実際に参照したい場合はどうでしょうか。正規表現をコンパイルするにはどうすればよいですか?

4

5 に答える 5

5

$問題は学術的です-とにかく正規表現にアンカーは必要ありません。改行とその前の文字の間のギャップのみが一致する\nため、改行を一致させるために使用する必要があります。$

編集:私が言おうとしているのは、あなたがそのように使う必要は決してない$ということです。ある行から次の行にまたがる一致は、何らかの方法で行区切り記号を使用する必要があります。あなたの例を考えてみましょう:

/^\[INFO\]$(.*?)$\[INFO\]/ms

これがコンパイルされた場合(.*?)、は最初の改行を消費することから始まり、一致するまで続行し\nxyz、2番目$が成功します。しかし、次の文字は改行であり、正規表現はを探している[ので、それは機能しません。バックトラック後、(.*?)はしぶしぶもう1文字(2番目のラインフィード)を消費しますが、$失敗します。

EOLを他のものと一致させようとするときはいつでも、一致し$なければならない最初の「もの」はラインフィードになるので、代わりにそれを一致させてみませんか?これが、Perl正規表現コンパイラが正規表現内の変数名として解釈しようとする理由$\です。行末アンカーの後に行区切り文字ではない文字を続けることは意味がありません。

于 2010-05-20T18:55:33.063 に答える
4

perlfaq6の回答に基づく-異なる線上にある2つのパターン間の線をどのように引き出すことができますか?、ワンライナーは次のようになります。

perl -0777 -ne 'print $1,"\n" while /\[INFO\]\s*(.*?)\s*\[INFO\]/sg' file.txt

スイッチは-0777ファイル全体を一度に丸呑みします。

ただし、抽出するタグを柔軟に選択できるサブルーチンを使用している場合は、File::Slurpモジュールを使用すると作業が少し簡単になります。

use strict;
use warnings;
use File::Slurp qw/slurp/;

sub extract {

    my ( $tag, $fileName ) = @_;
    my $text = slurp $fileName;

    my ($info) = $text =~ /$tag\s*(.*?)\s*$tag/sg;
    return $info;
}

# Usage:
extract ( qr/\[INFO\]/, 'file.txt' );
于 2010-05-20T21:04:35.950 に答える
4

正規表現がトリッキーになりすぎると、おそらく間違ったツールになります。ここでフリップフロップ演算子の使用を検討するかもしれません。左側が真になるまではfalseであり、右側が真になるまではtrueのままです。このように、個々の行を確認するだけで、抽出を開始および終了する場所を選択できます。

my $string = <<'HERE';
[INFO]
xyz
[INFO]
HERE

open my $string_fh, '<', \$string;

while( <$string_fh> )
    {
    next if /\[INFO]/ .. /\[INFO]/;
    chomp;

    print "Extracted <$_>\n";
    }

Perl 5.10を使用している場合は\R、正規表現で終わる一般化された行を使用できます。

use 5.010;

my $string = <<'HERE';
[INFO]
xyz
[INFO]
HERE

my( $extracted ) = $string =~ /(?:\A|\R)\[INFO]\R(.*?)\R\[INFO]\R/;

print "Extracted <$extracted>\n";

行末アンカーに引っ掛からないでください。

于 2010-05-21T00:48:22.893 に答える
1

多分/x修飾子は助けることができます:

m/ ^\[INFO\] $ # Match INFO line
   \n
   ^ (.*?) $ # Collect desired line
   \n 
   ^ \[INFO\] # Match another INFO line
/xms

私はそれをテストしていないので、おそらくデバッグする必要があります。$しかし、これにより、シンボルが変数として補間されるのを防ぐことができると思います。

于 2010-05-31T23:58:34.900 に答える
1

私はアラン・ムーアの答えを受け入れましたが(ライアン・トンプソンの答えもうまくいかなかったので、1つしか受け入れられませんでした)、コメントや議論に埋もれていたので、解決策を完全に明確にしたいと思いました。次のPerlスクリプトは、いずれかの文字がドル記号を進める場合、Perlが$を使用して変数を補間していること、および補間をオフにすると$がEOLとして扱われることを示しています。

use strict;
use warnings;

my $x = "[INFO]\nxyz\n[INFO]";
if( $x =~ /^\[INFO\]$\n(.*?)$\n\[INFO\]/m ) {
    print "'$1' FOUND\n";
} else {
    print "NO MATCH FOUND\n";
}

if( $x =~ m'^\[INFO\]$\n(.*?)$\n\[INFO\]'m ) {
    print "'$1' FOUND\n";
} else {
    print "NO MATCH FOUND\n";
}

if( $x =~ m/ ^\[INFO\] $ # Match INFO line
\n
^ (.*?) $ # Collect desired line
\n 
^ \[INFO\] # Match another INFO line
/xms ) {
    print "'$1' FOUND\n";
} else {
    print "NO MATCH FOUND\n";
}

スクリプトは次の出力を生成します。

Use of uninitialized value $\ in regexp compilation at t.pl line 5.
Use of uninitialized value $\ in regexp compilation at t.pl line 5.
NO MATCH FOUND
'xyz' FOUND
'xyz' FOUND
于 2010-06-02T17:44:34.967 に答える