
コマンドラインで大量のテキストを解析し、すべての(ネストされた)テキスト引用符を空白に置き換える必要があります。引用符は特定の構文で表示されます[quote=username]quoted text[/quote]
。
入れ子になった引用符を含む入力の例は次のとおりです。
text part 1 [quote=foo] outer quote 1 [quote=bar] inner quote [/quote] outer quote 2 [/quote] text part 2 [quote=foo-bar] next quote [/quote] text part 3
予想される出力は次のとおりです。
text part 1 text part 2 text part 3
の助けを借りてこの問題どういうわけか動作させましたが(上記の出力を得ました)、sed ':b; s/\[quote=[^]]*\][^[\/]*\[\/quote\]/ /g; t b'
中間部分( ]には引用符または同じ文字を[^[\/]
含めることができるため問題があります。[
]
つまり、sed
入力がたとえば次のような場合、私のコマンドは機能しません。
text part 1 [quote=foo] outer quote 1 [quote=bar] inner quote [foo] [/quote] outer quote 2 [/quote] text part 2 [quote=foo-bar] next quote [/quote] text part 3
1つの問題は、sed
貪欲な修飾子をサポートしていないようで、可能な限り長い一致が常に入力からキャプチャされることです。扱いにくいㅏ)ユーザー名と雨)一般的な引用。
私はこれがsed
この問題のための最善のツールではなく、そのようなことをすることができないかもしれないと思います。たとえば、おそらく。perl
それともawk
もっとうまくいくでしょうか?
今最後の質問は、この問題を解決するための最良かつ効率的な方法は何ですか?
答え1
入力に文字が含まれていないことがわかっている場合は、次のことができます<
。>
sed '
# replace opening quote with <
s|\[quote=[^]]*\]|<|g
# and closing quotes with >
s|\[/quote\]|>|g
:1
# work our way from the inner quotes
s|<[^<>]*>||g
t1'
<
または、文字を含めることができる場合は、>
次のスキームを使用してエスケープできます。
sed '
# escape < and > (and the escaping character _ itself)
s/_/_u/g; s/</_l/g; s/>/_r/g
<code-above>
# undo escaping after the work has been done
s/_r/>/g; s/_l/</g; s/_u/_/g'
AND perl
、再帰正規表現の使用:
perl -pe 's@(\[quote=[^\]]*\](?:(?1)|.)*?\[/quote\])@@g'
またはあなたが言及したように:
perl -pe 's@(\[quote=.*?\](?:(?1)|.)*?\[/quote\])@@g'
を使用すると、perl
オプションを追加して複数行の入力を処理できます-0777
。の場合、sed
コードの前に次のプレフィックスを追加する必要があります。
:0
$!{
N;b0
}
これにより、入力全体がパターン空間にロードされます。
答え2
私はこれを確認し、それは私のために働いた。代わりに別の一時モードを選択することもできますfoobar
。このモードがないと、タグ間sed
のすべてのエントリが削除され、1つだけ残ります。text part 1 text part 3
sed -e 's/\/quote\]/foobar\]/3' -e 's/\[.*\/quote\]//' -e 's/\[.*foobar]//' testfile
代わりtestfile
にパイプすることができればcat
答え3
すべての開始引用符でカウンター変数を増やし、すべての閉じる引用符でカウンター変数を減らす小さなスクリプトです。カウンタ変数が大きい場合は、0
テキストの断片をスキップします。
#!/bin/bash
# disable pathname expansion
set -f
cnt=0
for i in $(<$1); do
# start quote
if [ "${i##[quote=}" != "$i" ] && [ "${i: -1}" = "]" ]; then
((++cnt))
elif [ "$i" = "[/quote]" ]; then
((--cnt))
elif [ $cnt -eq 0 ]; then
echo -n "$i "
fi
done
echo
出力:
$ cat q1
text part 1 [quote=foo] outer quote 1 [quote=bar] inner quote [/quote] outer quote 2 [/quote] text part 2 [quote=foo-bar] next quote [/quote] text part 3
$ ./parse.sh q1
text part 1 text part 2 text part 3
$ cat q2
text part 1 [quote=foo] outer quote 1 [quote=bar] inner quote [foo] [/quote] outer quote 2 [/quote] text part 2 [quote=foo-bar] next quote [/quote] text part 3
$ ./parse.sh q2
text part 1 text part 2 text part 3
答え4
POSIX sed
ここの詳細な指示に従ってこれを行うことができます。このソリューションは、表示された両方の入力に適用されます。必要な変換を達成するために改行をマーカーとして使用するため、入力制限は複数行ではありません。
$ sed -e '
:top
/\[\/quote]/!b
s//\
&/
s/\[quote=/\
\
&/
:loop
s/\(\n\n\)\(\[quote=.*\)\(\[quote=.*\n\)/\2\1\3/
tloop
s/\n\n.*\n\[\/quote]//
btop
' input.txt