web-dev-qa-db-ja.com

sed / regexesのパターン一致優先順位を逆にする

次のコマンドを検討してください。

echo "string.with.dots" | sed 's/\(.*\)\.\(.*\)/\1\n\2/'

(最後の.までの任意の文字を最初のキャプチャグループに一致させ、その後の文字を2番目のキャプチャグループに一致させます。)

この出力:

string.with
dots

適切な組み合わせでアンカーを使用すると、このような動作を逆転させることができると考えました(つまり、最初のキャプチャグループではstringで、2番目のキャプチャグループではwith.dotsでした)。

echo "string.with.dots" | sed 's/^\(.*\)\.\(.*\)/\1\n\2/'
echo "string.with.dots" | sed 's/^\(.*\)\.\(.*\)$/\1\n\2/'
echo "string.with.dots" | sed 's/\(.*\)\.\(.*\)$/\1\n\2/'

すべての出力:

string.with
dots

パターンマッチングの実装方法はわかりませんが、文字列の末尾に近いパターンではなく、文字列の先頭に近いパターンに常に特権を与えているようです(^が存在するか、$が欠落しているにもかかわらず)。

どうすればこの動作を変更できますか(つまり、この例にハードコーディングされたソリューションを書く方法ではなく、パターンマッチングの優先順位をsedまたは正規表現に逆にする方法) 、 可能なら?

5
kos

2つのrevを追加し、\1\2を交換します。

echo "string.with.dots" | rev | sed 's/\(.*\)\.\(.*\)/\2\n\1/' | rev

出力:

 string 
 with.dots 
1
Cyrus

必要なものを取得するには、これを試してください:

sed -r 's/^([^.]*)\.(.*)/\1\n\2/'

テスト:

$ echo "string.with.dots" | sed -r 's/^([^.]*)\.(.*)/\1\n\2/'
string
with.dots

sedは貪欲に一致するため、sed 's/\(.*\)\.\(.*\)/\1\n\2/'を使用している間は、最初のキャプチャグループとして最後の.に貪欲に一致し、2番目として.の後の残りに一致します。

sed式で、sedが欲張りになるのを止めるには、いくつかの代替案を検索する必要があります。最初から最初のグループ(.)として[^.]*に一致し、2番目として最初の一致後のものを一致させました。

.の周りのすべての部分を別々の行にしたい場合:

$ echo "string.with.dots" | sed -r 's/^([^.]*)\.([^.]*)\.(.*)/\1\n\2\n\3/'
string
with
dots
3
heemayl

Bash parameter expansion を使用して逃げることができるかどうか疑問に思います

$ s="string.with.dots"
$ echo "${s%%.*}"; echo "${s#*.}"
string
with.dots
$ echo "${s%.*}"; echo "${s##*.}"
string.with
dots
1
glenn jackman