オンラインで2番目の出現を置換


12

ファイルのリストがあります:

./a.temp.txt     ./a.temp.txt
./a/b.temp.txt   ./a/b.temp.txt
./a/b/c.temp.txt ./a/b/c.temp.txt

そしてtemp.、各行のを削除したいのですが、2番目の出現だけなので、ファイルは次のようになります。

./a.temp.txt     ./a.txt
./a/b.temp.txt   ./a/b.txt
./a/b/c.temp.txt ./a/b/c.txt

どうすればよいですか?


いずれかの行に3番目または4番目のオカレンスがある可能性はありますか?これらはそのままにしておく必要がありますか?
ジェームズ

私の場合は、古いファイル名を新しいファイル名に一致させるため、各行に2回しか出現しません。そして、2番目のものだけが変更されます。
nobe4

回答:


10

通常、とを使用して\zs、何かのN番目の出現に一致させることができます\{N}。に例が示されてい:help \zsます。

あなたの場合、コマンドは次のようになります:

:%s/\(.\{-}\zstemp\.\)\{2}//

verymagicフラグを使用すると、正規表現を減らすことができます%s/\v(.{-}\zstemp.){2}//
nobe4

8

これは次のようにするとはるかに簡単になりますsed

sed 's/\.temp\././2'

Vimでは貪欲でないマッチングが必要であり、3番目、4番目などのを置き換えるようにメソッドを拡張するのは簡単ではありませんtemp。しかし、あなたが主張すればそれは可能です:

:%s/\.temp\..\{-}\.\zstemp\.//

sedソリューションを提供してくれてありがとう、これを各行に適用することは可能だと思いますか?
nobe4 2016

@ nobe4どういう意味かわかりません。 sedスクリプトを入力の各行に順番に適用します。
佐藤桂

はい。ただし、外部プログラムに行を渡して結果を返すことができます。
nobe4 16

2
Vimからですか?もちろん、sed他のプログラムにパイプするのと同じように、パイプを使ってラインをパイプできます。Fiの::%!sed 's/\.temp\././2'sedUNIXフレンドリーでは、入力を読み取り、stdin結果をに書き込みますstdout
佐藤桂

8

後読みでこれを行うこともできます。

:%s/\(temp\..*\)\@<=temp\.//

最初の後にすべてのオカレンスを削除したい場合gは、最後にフラグを追加できます。

\(\)\@<=\(との間のパターンを検索します\)が、見つかったテキストを一致に追加しません。

詳細については:h \@<=、を参照してください。


6

@Meshpiで既に提案されているようにマクロを使用できます。しかし、これは同じことを達成できる別の方法です。

02/temp^Mdwx+

0-行頭に移動

2 / temp-tempを検索し、2番目の出現に移動します

^ M-これはEnterキーを押すだけです

dw-単語(temp)を削除する

x-「。」を削除します

+-次の行の先頭に移動

そして、あなたはそれを最後まで繰り返すことができます。そして、同じことを行う方法はもっとたくさんあります。


6

このソリューションはTessellatingHecklerのソリューションに似ていますが、削除する必要があるパターンに簡単に適応できます。

:g/temp\./normal 2ngnd

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

  1. :g/temp\./ 「temp」に一致するすべての行。
  2. normal 通常モードで以下を実行します
    1. 2n パターンの2番目の出現を見つける
    2. gn それを選択
    3. d それを削除します。

これは、に与えられるパターンが何であっても機能し:gます。 normalと省略される場合がありますnormgndと同等dgnです。 編集:実際に2ngndはと同等d2gnです。

グローバルコマンドのその他の例については、Vim Tips Wikiを参照してください。


4

Vimでは、マッチングを実行する前/後/後の列を定義できます:help \%c

:%s/\%>17c\.temp/g

これ.tempにより、現在のバッファのすべての行の17列目以降に見つかったすべてが削除されます。


注1:/gサンプルでは必要ありません。

注2:この便利な機能をqmvで頻繁に使用しています。おすすめ!


きちんと、私はプラグインを作ることを考えていました、しかしこれはいいです!
nobe4 2016

Vimはすでに...たくさんのことを行います
romainl

確かに、私はこのツールを知りませんでした。そして、スクリプトの少しはいつも楽しいです!
nobe4 16

6
あなたは、物事のこの種のを気にした場合、@ nobe4、も参照vidirしてvipeからmoreutilsのパッケージ。
佐藤桂

4

これは実際にはかなり単純です。2番目のtempに一致させるには、「temp」の後に何かが続くことを許可し、もう一度tempを探します。

%s/.*temp.*\zstemp\.

\zs「ここから選択を開始する」という意味で、マッチの最初の部分(2番目の臨時雇用者の前のすべて)は削除されません。これは実際、私が学んだばかりの非常に便利な機能です。これがない場合、正規表現は次のようになります。

:%s/\(.*temp.*\)temp\./\1

temp1行に3 つ以上ある場合、レシピは2番目ではなく最後の1つを削除します。欲のせいにしなさい。:)
lcd047 2016

2
はい、これは貪欲なので、最後のものを削除します。しかし、OPは言ったMy case was to match old filename to new filename, so only 2 occurrences will be on each line. And only the second one should change
ジェームズ

2

正規表現の代わりに、次のコマンドを実行します。

  • 行末にジャンプ
  • 後方検索 temp
  • 5文字削除

そしてそれをすべての行で実行します:

:g//normal $?temp^[5x

NB。^[特別で、Escapeキーを押すことを表します。あなたはそれを次のように入力します:Ctrl-q <Esc>


しかし、私がまだ提案していないと思う正規表現オプションは、行の最後にアンカーされたtemp.以外のすべてが続くマッチ.です。

:%s/temp\.\([^.]\+\)$/\1/

これはtemp.txt行末で一致し、txt少しだけ置き換えます。


1

カーソルを左上から開始してマクロを記述します。 qq4f.dfpq

次に、使用して残りの行を選択し、Vそれらの行でマクロを実行します:'<,'>norm!@q

これは、テキスト形式が2番目の温度の前のドット数に関して同じままの場合にのみ機能します。


5
マクロをより堅牢にするには、検索を使用する必要があります。n代わりに4f.、ファイル名にドットが多い場合、マクロは失敗するか、削除してはいけないものを削除する可能性があります。
スタトックス

1

1つだけでなく2つの正規表現を使用することを妨げるものはありません。つまり、最初の正規表現を変更してから、列を交換します。

:%s/\.temp//|%s/^\(\S\+\)\(\s\+\)\(\S\+\)/\3\2\1/

それほど賢くはないかもしれませんが、とても読みやすいと思います。


0

私の試み

:%norm 4ftdwx

:%norm ......... execute in normal mode over the whole file  
4ft ............ the 4th t matches the start of the second temp
dw ............. deletes the current word
x .............. deletes the dot
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.