0

私は正規表現を持っています:

BEGIN\s+\[([\s\S]*?)END\s+ID=(.*)\]

以下のテキストから複数行のテキストとIDを選択します。プレフィックスが付いたIDのみを選択したいのですが、最初X_に変更ID=(.*)するID=(X_.*)と、必要に応じて3番目からではなく2番目のペアから選択されます。誰かが私が正しい表現を得るのを手伝ってくれませんか?

テキストの例:

BEGIN [
text a
END ID=X_1]

BEGIN [
text b
text c
END ID=Y_1]

text aaa
text bbb

BEGIN [
text d
text e
END ID=X_2]

text xxx

BEGIN [
text bbb
END ID=X_3]
4

3 に答える 3

1

.*人々が言い続けるように、すべてをむさぼり食うのは ではありません[\s\S]*?.*(OPが言ったように)ドットが改行と一致しないため、それはできません。

正規表現のEND\s+ID=(X_.*)\]一部が 2 番目のブロックの最後の行と一致しない場合、そのブロックを破棄して 3 番目のブロックからやり直すことを期待しています。それが、最短一致を作成するために必要なことです。

実際には、行の先頭に戻り[\s\S]*?、代わりにそれを消費させます。END\s+ID=(X_.*)\]そして、3 番目のブロックの最後の行である一致する場所が見つかるまで消費を続けます。

次の正規表現は、行ごとに照合し、それぞれをチェックして で始まるかどうかを確認することで、この問題を回避しますEND。これにより、一度に 1 つのブロックに一致が効果的に制限されます。

(?m)^BEGIN\s+\[[\r\n]+((?:(?!END).*[\r\n]+)*)END\s+ID=(X_.*)\]

^以前は各一致を行の先頭に固定していたため、(?m)複数行モードをオンにしていたことに注意してください。しかし、私は単一行/DOTALL モードをオンにしませんでした (あなたもすべきではありません)。

于 2012-08-03T10:00:03.550 に答える
1

ブロック内に改行がなくBEGIN/ENDステートメントがその行の最初の非スペースであると仮定すると、次のように正規表現を記述します (Perl 表記法; 区切り文字を変更し、コメント、空白、/x修飾子を使用する場合は削除します別のエンジン)

m{
  \n \s* BEGIN \s+ \[          # match the beginning
     ( (?!\n\s*\n) .)*?        # match anything that isn't an empty line
                               # checking with a negative look-ahead (?!PATTERN)
  \n \s* END \s+ ID=X_[^\]]* \] # the ID may not contain "]"
}sx                            # /x: use extended syntax, /s: "." matches newlines

コンテンツが何でもある場合は、すべてのブロックのリストを作成し、それらを grep するのが最善かもしれません。この正規表現は、任意のブロックに一致します。

m{ (
  BEGIN \s+ \[
  .*?              # non-greedy matching is important here
  END \s+ ID=[^\]]* \] # greedy matching is safe here
) }xs

(必要に応じて改行を追加します)

次に、この正規表現に一致する一致のみを保持します。

/ID = X_[^\]]* \] $/x  # anchor at end of line

これを行わないと、バックトラッキングによって正しい一致が妨げられる可能性があります([\s\S]*?含むことができますEND ID=X_)。あなたの正規表現は、 X_.*.

したがって、使用するBEGIN\s+\[([/s/S]*?)END\s+ID=(.*?)\]と — 余分な疑問符に注意してください — 1 つの一致は次のようになります。

BEGIN [
text b
text c
END ID=Y_1]

text aaa
text bbb

BEGIN [
text d
text e
END ID=X_2]

…で失敗する代わりにY_。貪欲な一致 (変更されていない正規表現) は、ファイル全体が一致する結果となるはずです:(.*)すべての文字を (ファイルの最後まで) 使い果たし、. が見つかるまで戻ります]

編集:

perls 正規表現エンジンを使用している場合は、次の(*FAIL)動詞を使用できます。

/BEGIN\s+\[(.*?)END\s+ID=(X_[^\]]*|(*FAIL))\]/s

「で始まるIDを持っているX_か、一致に失敗します」. END ID=X_1]ただし、これはデータ内の -like ステートメントの問題を解決しません。

于 2012-08-03T06:30:40.897 に答える
0

あなたのマッチがENDブロックを超えてこぼれないように、あなた.*をaに変更してください(つまり、非]sにマッチします)。[^\]]*BEGIN\s+\[([^\]]*?)END\s+ID=(X_[^\]]*)\]

于 2012-08-03T06:17:59.537 に答える