sedを使用してグローバルマッチをネストする方法は?

sedを使用してグローバルマッチをネストする方法は?

私がするなら:

sed 's/match/replace/g'

私はそれがsed取り替えることを知っている。変えるすべてのイベントについてマッチ行に。しかし、もし…?

echo "match <please dont match this?>" |
sed 's/match/replace/g'

...または...

echo "never match unless <the match is somehow delimited?>" |
sed 's/match/replace/g'

testループまたはbranchループを使用して個別に再帰的に一致させることはできますが、グローバル一致s///gコンテキストで行の一部をスキップするにはどうすればよいですか?

ベストアンサー1

内容はsedこれです貪欲。すべての状況でできるだけ多く食べます。これは、s///g部分交換環境で利点を提供できます。あなたの\(グループ\) *0以上文字列一致は、sedいずれの場合でも最初の文字列をグローバルに飲み込みます。gしたがって、安定して定義できれば/これと一致/ |これをスキップしてください。これができる場合:

sed 's/\([^<>]*<\)*\(match  *\)*\(remove  *\)*/\1/g
     s/.\{,45\}[^ ]*/&\
/g;  s/\(\n\) */\1/g
' <<INPUT
Never remove any match unless <the match \
you want to remove is somehow delimited.> \
And you can remove any match <per your match \
delimiter as many times as your match occurs \
within the match delimiters.>
INPUT

出力

Never remove any match unless <the you want to
is somehow delimited.> And you can remove any
match <per your delimiter as many times as your
occurs within the delimiters.>

シェルがここのドキュメントのバックスラッシュから改行をエスケープするので、入力は1行です。sed45文字に分割します。(与えたり受けたり)罫線を作成して印刷します。それにもかかわらず、見てわかるように、2つの条件のうちの1つが発生するたびにマッチまたは削除する外に一つ<...>境界はそのまま残りますが、すべての内部境界は出力から削除されます。

sedこれは一致する項目に適用される欲求関数です。*0以上移流。否定するために1つまたは2つのステップを追加するだけであるにもかかわらず、代替が同じように機能することを不可能にするのはこの欲です。

これがどのように機能するかを明確にするために代替を実行できます。ところで、直接適用すると、通常はあまり役に立ちません。

printf '%s %s\n' '<321Nu0-9mber123>' \
                 'String321strinG' \
                 '<321Nu0-9mber123>' \
                 'String321strinG' |
sed 's/\(<[^<>]*>\)*[0-9]*/\1!/g'

出力

<321Nu0-9mber123>! !S!t!r!i!n!g!s!t!r!i!n!G!
<321Nu0-9mber123>! !S!t!r!i!n!g!s!t!r!i!n!G!

したがって、sedグローバルパターンで線を一致させるときに特徴的な欲を維持しながら、できるだけ多くのパターンを一致させようとします。モードが貪欲なときの副作用0以上指定された発生が行の一部と一致しません。それでも一致- 空の文字列と一致します。〜サイ行部分のバイトを一致させることはできません。

上から見ればわかるけど<...>文字列は影響を受けませんが、その中の数字はひも...消えただけでなく、sedキャラクター別にバンが挿入されました。これはsed、空の文字列とのすべての一致を反映します。これがこの技術がg世界的に有用な理由です。定義する1つの代わりに試合を置き換えてください。

仕組みは次のとおりです。

printf '%s\t%s\n' '<321Nu0-9mber123>' \
                'String321strinG' \
                '<321Nu0-9mber123>' \
                'String321strinG' |
sed 's/[0-9]/&\n/g;s/\(<[^<>]*>\)*\n*/\1/g;y/\n/0/'

出力

<302010Nu00-90mber102030>       String321strinG
<302010Nu00-90mber102030>       String321strinG

<これは非常に単純なケースで、andに現れるすべての数字にゼロを追加します>が、実際には\nグローバル置換を実行するためにこの方法でewline文字を使用できます。どのマッチ。基本原則は次のとおりです。

  1. するsed 's/match/&\n/g'
  2. それからsed 's/\(match group\)*\n*/\1/g'
  3. 最後にすることsed 's/match\n/replace/g'

もちろん、この例は単純なリストの例(<常に一番上にある)のみを示しています>。巣も考慮する必要があります。もっと難しいです。時にはもっと難しいです。しかし、うーん...

sed 's/\([{}]\)\([^{}]*[{}]*\1\)*/\n<&>/g
' <<\INPUT
{{{1!}{2!}{3!}}}outside!{{{4!}}{{5!}}}
INPUT

出力

<{{{1!}{2!}{>3!
<}}}>outside!
<{{{4!}}{{>5!
<}}}>

改行文字でグループを直列化します。同じタイプの区切り文字を連続して2回積み重ねると、各一致グループに一致する区切り文字が交互に動作します。(少なくとも2回)副作用は葉巻と終値を比較することです。つまり、単純化のために、残りの部分では、すべての読者が入力を準備するために同様の方法を使用し、入れ子にすることは問題ではないと仮定します。

本質的に、これらすべての基本的なアイデアは優先順位を一致させることです。最初の例は、削除された文字列と一致させる前に、開いている区切り文字の直前に区切り文字を持たない文字グループと一致しようとする方法で機能します。最初のセットが一致した場合、交換が完了すると、一致するすべてのセットのみが独自に交換できるため、交換が困難になる理由になります。削除する方が簡単です。一致するものを交換から除外しても大丈夫だからです。

また、sed他のパターンよりも特定のタイプのパターンを強調します。これを行うときは、次のことを理解することが重要です。本当に指定されたパターンは、常にパターンよりも多くの重みを持ちます。*0以上ケース。したがって、グローバルモードでこれらの項目を使用するときは、その項目のみを使用*したり、まったく使用しないでください。それ以外の場合は、すべてのグループをまったくスキップできます。

方法は次のとおりですsed

おすすめ記事