次の行を含むファイルがあります。
ABCDABCBCBBBCBCDDBBBBBBBBBBBBBBBBBBBBBBBBBXYZ
ABCDCCCBCCBBBBBBBBBBBBBBBBBBBBBBXYZ
ABCDACDCDCCCCBBBBBBBBBBBBBBBBBBBBBBBBXYZ
そして私は欲しい
BBBBBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBBBXYZ
したがって、目標は、ABCD
連続した4つのsが最初に表示されたときから始まり、すべての項目を削除することですB
。すべての行はで始まることが保証され、s以前の「関連」チェーンが終了する前に行にABCD
「去る」ことはあってはなりません。BBBB
B
XYZ
私は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*
指示できます。sed
BBBB
その他特徴。
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
ちなみに、あなたのようなほとんどの単純なスクリプトは代わりに(または適切な場合はコマンドではなくステートメントを使用して)実行できますが、代わりにsed
perl regexを使用します。perl -p -e
sed
perl -n -e
print
sed -n
p
着替える(sedのデフォルト値)またはERE(sed -E
)。 forとは異なり、次の引数がスクリプトであることを示すのはオプションではsed
ありません。-e
perl
から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