6

foo_barfoo_abc_barという 2 つの文字列があります。両方合わせたいですし、前者が合っていれば=記号で強調したいです。だから、私の推測は次のとおりでした:

echo 'foo_abc_bar' | sed -r 's/(foo).*(abc)?.*(bar)/\1=\2=\3/g'
> foo==bar

また

echo 'foo_abc_bar' | sed -r 's/(foo).*((abc)?).*(bar)/\1=\2=\3/g'
> foo==

しかし、上記の出力が示すように、それらのどれも機能しません。

文字列に含まれている場合に一致する、または含まれていない場合はスキップするオプションのグループを指定するにはどうすればよいですか?

4

2 に答える 2

8

ソリューション:

echo 'foo_abc_bar' | sed -r 's/(foo)_((abc)_)?(bar)/\1=\3=\4/g'

以前の試みがうまくいかなかった理由:

.*は貪欲であるため、(foo).*(abc)?.*(bar)一致しようとする正規表現'foo_abc_bar'(foo)に一致し'foo'.*最初に文字列の残りの部分に一致します ( '_abc_bar')。正規表現は、必要なグループに到達するまで続行されますが、(bar)これは失敗します。その時点で、正規表現は、.*. これは、最初のグループが一致.*するだけになるまで発生'_abc_'し、その時点で最後のグループが一致する可能性があり'bar'ます。したがって'abc'、文字列の がキャプチャ グループで一致するのではなく、非キャプチャで一致し.*ます。

私の解決策の説明:

最初で最も重要なことは、 を に置き換える.*こと_です。セパレータが何であるかがわかっている場合は、任意の文字列に一致させる必要はありません。次に行う必要があるのは、文字列のどの部分が省略可能かを正確に把握することです。文字列'foo_abc_bar''foo_bar'が両方とも有効な場合'abc_'、真ん中はオプションです。を使用して、これをオプションのグループに入れることができます(abc_)?。最後のステップは'abc'、キャプチャ グループに文字列がまだ残っていることを確認することです。これは、その部分を追加のグループでラップすることで実行できるため、((abc)_)?. 次に、余分なグループがあるため、置換を調整する必要があります。\1=\2=\3使用する代わりに、文字列になり\1=\3=\4ます\2'abc_'(一致した場合)。ほとんどの正規表現の実装では、非キャプチャ グループを使用し、引き続き を使用することもできまし\1=\2=\3たが、sed は非キャプチャ グループをサポートしていないことに注意してください。

別の方法:

上記の正規表現は最も明示的であるため、最善の策だと思います(関心のある正確な文字列にのみ一致します)。ただし、貪欲な繰り返し (できるだけ多くの文字に一致) の代わりに、遅延繰り返し (できるだけ少ない文字に一致) を使用することで、上記の問題を回避することもできます。.*を toに変更することでこれを行うことができる.*?ため、式は次のようになります。

echo 'foo_abc_bar' | sed -r 's/(foo).*?(abc).*?(bar)/\1=\2=\3/g'
于 2013-05-23T16:36:51.470 に答える
1

多分あなたは単に使うことができます:

echo 'foo_abc_bar' | sed -r 's/(foo|bar|abc)_?/\1=/g'
echo 'foo_bar' | sed -r 's/(foo|bar|abc)_?/\1=/g'

> foo=abc=bar=
> foo=bar=

foo==barこれはあなたが得ることを避け、時には試合の前に、時には試合の後にfoo_bar強調を示すのは少し奇妙だと思いました.=

于 2013-05-23T16:44:08.820 に答える