1行で2つのパターンを見つけてパターンを削除し、それらの間の順序を指定します。

1行で2つのパターンを見つけてパターンを削除し、それらの間の順序を指定します。

次の行を含むファイルがあります。

ABCDABCBCBBBCBCDDBBBBBBBBBBBBBBBBBBBBBBBBBXYZ
ABCDCCCBCCBBBBBBBBBBBBBBBBBBBBBBXYZ
ABCDACDCDCCCCBBBBBBBBBBBBBBBBBBBBBBBBXYZ

そして私は欲しい

BBBBBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBBBXYZ

したがって、目標は、ABCD連続した4つのsが最初に表示されたときから始まり、すべての項目を削除することですB。すべての行はで始まることが保証され、s以前の「関連」チェーンが終了する前に行にABCD「去る」ことはあってはなりません。BBBBBXYZ

私はsedこれに近いバリエーションを試しました。

sed 's/ABCD.*BBBB//g' filename 

XYZ最後のパターンまでは止まらないのであげるようですがBBBB、最初のパターン以降は止めたいです。

どんな助けでも大変感謝します! !

答え1

sedあなたが疑うように、あなたの方法が失敗する理由は、それがsed正規表現に基づいており、これが「貪欲」であるからです。つまり、説明できる最も長い文字列を一致させようとします。

だからこれが課題かもしれませんawk。次のプログラムを検討してください。

awk '{n=index($0,"BBBB"); print substr($0,n+4)}' input.txt

BBBB$0次に、現在の行で部分文字列(で示されている)が最初に表示される場所を見つけ、その場所をに保存しますn。次に、その位置から始めて、B行の最後まで4(最初の4秒を削除するため)を加えた行の部分を印刷します。

ABCD例の入力からわかるように、ここにはスタートモードへの言及はありません。みんな行はで始まりますABCD。この場合、行の先頭から(最初の4--を含む)パターンまですべての内容を削除すれば十分ですB。仮定が間違っている場合、特にBBBB以前に発生する可能性がある場合、期待ABCDどおりに機能しません。

答え2

何をすべきか尋ねるawkがある(remove everything starting with the ABCD up to, and including, the first occurence of 4 consecutive Bs.)の場合は次のようになります。

$ awk -v beg='ABCD' -v end='BBBB' '
    { gsub(end,"\n") }
    match($0,beg"[^\n]+\n") { $0=substr($0,1,RSTART-1) substr($0,RSTART+RLENGTH) }
    { gsub(/\n/,end) }
1' file
BBBBBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBBBXYZ

これは、ABCDが行の最初であるか、BBBBがその前に現れるかどうかに関係なく機能します。

$ echo 'xyz BBBB foo ABCD bar BBBB etc BBBB anon' |
    awk -v beg='ABCD' -v end='BBBB' '{gsub(end,"\n")} match($0,beg"[^\n]+\n"){$0=substr($0,1,RSTART-1) substr($0,RSTART+RLENGTH)} {gsub(/\n/,end)} 1'
xyz BBBB foo  etc BBBB anon

答え3

シーケンスが一度だけ発生した場合は、最初の前のシーケンスのみを削除するようにBBBB*指示できます。sedBBBBその他特徴。

sed 's/^ABCD.*[^B]BBBB//'

BBBBシーケンスが1行に1回だけ開始される場合は、操作を実行する必要があります。

次の文字列では機能しません。

エイビーシーディBBBBFBBBBXYZ

これは2回発生する状況で、BBBB前にBではないことがあるので、グリディアルゴリズムは2番目にもキャプチャすることになります。

答え4

問題は、sed正規表現が「欲張り」であることです(つまり、できるだけ多くの項目を一致させようとしています)。 sed一致の欲張りではない数量子はありませんが、一致したい項目の後に追加perlするだけです。?例えば

$ sed 's/ABCD.*BBBB//g' input.txt 
XYZ
XYZ
XYZ
$ perl -p -e 's/ABCD.*?BBBB//g' input.txt 
BBBBBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBBBXYZ

ちなみに、あなたのようなほとんどの単純なスクリプトは代わりに(または適切な場合はコマンドではなくステートメントを使用して)実行できますが、代わりにsedperl regexを使用します。perl -p -esedperl -n -eprintsed -np着替える(sedのデフォルト値)またはERE(sed -E)。 forとは異なり、次の引数がスクリプトであることを示すのはオプションではsedありません。-eperl

からman perlre

デフォルトでは、量子化されたサブパターンは「欲張り」です。つまり、パターンの残りの部分も一致するようにできるだけ多く一致します(特定の開始位置を指定)。できるだけ少ない回数で一致させるには、数量子の後に追加してください?。意味は変わらず、単に「貪欲な」ということに注意してください。

*?        Match 0 or more times, not greedily
+?        Match 1 or more times, not greedily
??        Match 0 or 1 time, not greedily
{n}?      Match exactly n times, not greedily (redundant)
{n,}?     Match at least n times, not greedily
{n,m}?    Match at least n but not more than m times, not greedily

関連情報