文字列の2番目から最後の空白文字より前のすべての文字を一致させる方法は?

文字列の2番目から最後の空白文字より前のすべての文字を一致させる方法は?

文字列「Abbey Street E.2 Buckfast Street」の下の文字列「Abbey Street E.2」を置き換えて、「Buckfast Street」という結果を得ようとしています。

私はそれを試しましたが、:s/[^ ]* [^ ]* //私が得たのは「距離」だけでした。

デフォルトでは、最後の空白文字から2番目の前のすべてを削除するには、置換コマンドを使用しようとしています。

私のオペレーティングシステムはMacOsで、vimを使用しています。

また、上記の置換コマンドの私の理解は、空白以外の文字を空白文字と一致させ、次に空白以外の文字を空白文字と一致させることです。そうですか?

答え1

sed(テストがより簡単な場所)では、必要な正規表現を作成できます。
Aは[^ ]*すべての単語と一致する必要があります(句読点がない場合)。だから:

$ a="Abbey Street E.2 Buckfast Street"
$ echo "$a" | sed 's/[^ ]*//'
 Street E.2 Buckfast Street

最初の単語が削除されます。出力には空白が残ります。その後、スペースも削除する必要があります。そして、同じ操作を3回繰り返して前の3つの単語を削除し、最後の2つの単語を保持します。

$ echo "$a" | sed 's/\([^ ]* \)\{3\}//'
Buckfast Street

しかし説明では、あなたはこう言いました。2番目の空白文字まで、それは違います。 6単語文から3単語を削除すると、代わりに3単語が残ります。最後の2つ

したがって、私たちは逆に作業する必要があり、正規表現の効果を確認するために各部分をキャプチャして別々に印刷します|==|

単語をキャプチャするための基本的なアイデアはを使用することです[^ ]*。はい、動作します(時々)。\'を避けるには、-Eを使用してください。

$ echo "$a" | sed -E 's/([^ ]*)(.*)/\1|==|\2/'
Abbey|==| Street E.2 Buckfast Street

.*最初の括弧に最初の単語をキャプチャし、2番目の括弧()に「残りのすべての単語」をキャプチャします。ただし、正規表現を逆に置き換えるには、次のようにします。

$ echo "$a" | sed -E 's/(.*)([^ ]*)/\1|==|\2/'
Abbey Street E.2 Buckfast Street|==|

ここで何が起こるのかは、すべてが.*キャプチャされ、次の部分がキャプチャされることです。若い文字(有効な結果です*)。私たちには少し必要です。アンカーまたはセパレータ、正規表現が特定の文字または特定の点の点と一致するように強制します。選択した単語が実際に存在するかどうかを確認するには、スペースを区切り文字として使用し、$ をアンカーとして使用できます。最後ひも:

$ echo "$a" | sed -E 's/(.* )([^ ]*)$/\1|==|\2/'
Abbey Street E.2 Buckfast |==|Street

一致した空白を繰り返します。最後の2つの単語:

$ echo "$a" | sed -E 's/(.* )([^ ]* [^ ]*)$/\1|==|\2/'
Abbey Street E.2 |==|Buckfast Street

次に、維持および/または削除する部分を選択します。

$ echo "$a" | sed -E 's/(.* )([^ ]* [^ ]*)$/\2/'
Buckfast Street

もちろん、この時点で最初の部分をキャプチャする必要はありません。

$ echo "$a" | sed -E 's/.* ([^ ]* [^ ]*)$/\1/'
Buckfast Street

この ERE に対応する BRE は vim で動作します。

:s/.* \([^ ]* [^ ]*\)$/\1/

答え2

vimでは、次()のようなものをエスケープする必要があります。

:s/.* \(.\+ .\+$\)/\1/

空白が2つ以上ない場合、行は壊れます。

答え3

awkを使用して文字列の最後の2つの単語を印刷することもできます。

awk '{printf(NF>1)?$(NF-1)" "$NF"\n":(NF>0)?$NF"\n":""}'

例:

$ echo ""|awk '{printf(NF>1)?$(NF-1)" "$NF"\n":(NF>0)?$NF"\n":""}'
$ echo "1"|awk '{printf(NF>1)?$(NF-1)" "$NF"\n":(NF>0)?$NF"\n":""}'
1
$ echo "1 22"|awk '{printf(NF>1)?$(NF-1)" "$NF"\n":(NF>0)?$NF"\n":""}'
1 22
$ echo "1 22 333"|awk '{printf(NF>1)?$(NF-1)" "$NF"\n":(NF>0)?$NF"\n":""}'
22 333
$ echo "1 22 333 4444"|awk '{printf(NF>1)?$(NF-1)" "$NF"\n":(NF>0)?$NF"\n":""}'
333 4444

sedの場合は、次を使用します。

sed 's/^.*\s\([^ \t]\+\)\s\+\([^ \t]\+\)\s*$/\1 \2/g'

例:

$ echo " 1  22   3333  4444   "|sed 's/^.*\s\([^ \t]\+\)\s\+\([^ \t]\+\)\s*$/\1 \2/g'
3333 4444

少数の空白(またはタブ記号)を含む行は正しく処理する必要があり、行の末尾に余分な空白がある可能性があるため、この場合、出力は2行が空白の単語に分割され、複雑さが増します。 。ただし、この場合、1つの単語のみを含む行やスペースのみを含む行は含まれず、そのまま印刷されます。気にしますが、sedコマンドがより複雑になるので、ここではスキップします。


直す。

MacOS sedの場合、次のようになります(簡単にするためにタブを除外しました)。

sed 's/^.* \([^ ][^ ]*\)  *\([^ ][^ ]*\) *$/\1 \2/g'

例:

$ echo " 1  22   3333  4444   "|sed 's/^.* \([^ ][^ ]*\)  *\([^ ][^ ]*\) *$/\1 \2/g'
3333 4444

答え4

あなたが探しているものは次のとおりです。
:s/^\S*\s\S*\s\S*\s//
^は行の始まりを表し、
\ sは「スペース」(スペースまたはタブ)を表し
、\ Sは「スペースなし」を示します。

これは、次のように「省略」することができます。
:s/^\(\S*\s\)\{3\}//
「空白以外のすべての数」が3回発生し、その後に空白があることを示します。

これは「Abbey Street E.2」と一致して削除され、「Buckfast Street」は維持する必要があります。

関連情報