Gantikan kemunculan kedua secara online


12

Saya punya daftar file:

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

Dan saya ingin menghapus temp.pada setiap baris, tetapi hanya kejadian kedua , dengan demikian, file tersebut akan terlihat seperti:

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

Bagaimana saya harus melakukan ini?


Apakah mungkin bahwa akan ada kejadian ketiga atau keempat di jalur mana pun? Apakah ini harus tetap utuh?
James

Kasus saya adalah mencocokkan nama file lama dengan nama file baru, jadi hanya 2 kemunculan yang akan ada di setiap baris. Dan hanya yang kedua yang harus berubah.
nobe4

Jawaban:


10

Secara umum Anda dapat mencocokkan kemunculan Nth dari sesuatu yang menggunakan \zsdan \{N}. Ada contoh yang diberikan di :help \zs.

Dalam kasus Anda, perintahnya adalah:

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

dengan bendera verymagic Anda dapat mengurangi regex:%s/\v(.{-}\zstemp.){2}//
nobe4

8

Ini lebih mudah dilakukan dengan sed:

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

Dengan Vim Anda membutuhkan pencocokan non-serakah, dan tidak mudah untuk memperpanjang metode untuk menggantikan ke-3, ke-4, dll temp. Tapi itu bisa dilakukan jika Anda bersikeras:

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

Terima kasih telah memberikan solusi sed, apakah menurut Anda dimungkinkan untuk menerapkan ini pada setiap baris?
nobe4

@ nobe4 Tidak yakin apa yang Anda maksud dengan itu. sedberlaku skrip untuk setiap baris input pada gilirannya.
Sato Katsura

ya, tetapi Anda dapat mengirimkan baris ke program eksternal dan mendapatkan kembali hasilnya.
nobe4

2
Maksud Anda dari Vim? Tentu, Anda dapat menyalurkan saluran pipa sedseperti halnya Anda dapat menyalurkannya ke program lain. Fi: :%!sed 's/\.temp\././2'. seddi UNIX-friendly, ia membaca input dari stdindan menulis hasilnya stdout.
Sato Katsura

8

Anda juga dapat melakukan ini dengan melihat di belakang.

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

Jika Anda ingin menghapus SEMUA kejadian setelah yang pertama, Anda dapat menambahkan gtanda di bagian akhir.

\(\)\@<=Akan mencari pola apa pun di antara \(dan \)tetapi tidak akan menambahkan teks yang ditemukan ke kecocokan.

Lihat :h \@<=untuk info lebih lanjut.


6

Anda dapat menggunakan makro seperti yang disarankan @Meshpi. Tetapi, ini adalah cara lain Anda dapat mencapai hal yang sama.

02/temp^Mdwx+

0 - Pergi ke awal garis

2 / temp - Cari temp dan lanjut ke kejadian kedua

^ M - Ini hanya menekan tombol Enter

dw - hapus kata (temp)

x - hapus '.'

+ - Pergi ke awal baris berikutnya

Dan, maka Anda bisa mengulanginya sampai akhir. Dan, akan ada lebih banyak cara untuk melakukan hal yang sama.


6

Solusi ini mirip dengan TessellatingHeckler tetapi lebih mudah disesuaikan dengan pola apa pun yang harus dihapus.

:g/temp\./normal 2ngnd

Begini cara kerjanya:

  1. :g/temp\./ untuk setiap baris yang cocok dengan "temp."
  2. normal jalankan perintah berikut dalam mode normal
    1. 2n temukan arus kedua polanya
    2. gn pilih itu
    3. d dan hapus.

Ini akan bekerja untuk pola apa pun yang diberikan :g. normaldapat disingkat menjadi norm. gndsetara dengan dgn. Sunting: Faktanya 2ngndsetara dengan d2gn.

Lihat Vim Tips Wiki untuk lebih banyak contoh perintah global.


4

Di Vim, Anda dapat menentukan kolom sebelum / di / setelah yang Anda inginkan pencocokan Anda terjadi dengan :help \%c:

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

Ini akan menghilangkan setiap yang .tempditemukan setelah kolom 17 dari setiap baris dalam buffer saat ini.


Catatan 1: /gtidak perlu dengan sampel Anda.

Catatan 2: Saya sering menggunakan fitur praktis itu dengan qmv . Direkomendasikan!


Rapi, saya berpikir untuk membuat plugin, tapi ini bagus!
nobe4

Vim sudah melakukan banyak hal ...
romainl

Tentu, tetapi saya tidak mengetahui alat ini. Dan sedikit scripting selalu menyenangkan!
nobe4

6
@ nobe4 Jika Anda peduli tentang hal-hal semacam ini, lihat juga vidirdan vipedari paket moreutils .
Sato Katsura

4

Ini sebenarnya cukup sederhana. Untuk mencocokkan temp kedua, izinkan apa pun yang diikuti oleh "temp" diikuti oleh apa pun, lalu cari temp lagi.

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

The \zsberarti "Start seleksi sini" sehingga bagian pertama dari pertandingan (segala sesuatu sebelum suhu kedua) tidak dihilangkan. Ini sebenarnya fitur yang sangat berguna yang baru saja saya pelajari! Tanpa itu, regex harus terlihat seperti ini:

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

Jika ada lebih dari dua temppada satu baris resep Anda menghapus yang terakhir, bukan yang kedua. Salahkan keserakahan. :)
lcd047

2
Ya, ini serakah, dan karena itu menghapus yang terakhir. Namun, kata 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.
James

2

Alih-alih regex, saya akan pergi dengan perintah yang tidak:

  • Lompat ke ujung garis
  • Cari mundur untuk temp
  • Hapus 5 karakter

dan jalankan di setiap baris:

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

NB. ^[khusus dan mewakili penekanan tombol Escape; Anda mengetiknya dengan:Ctrl-q <Esc>


Tetapi opsi regex, yang saya pikir belum disarankan, adalah untuk mencocokkan temp.diikuti oleh apa pun kecuali a ., berlabuh ke akhir baris.

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

Yang akan cocok temp.txtdi akhir baris dan menggantinya dengan hanya txtbit.


1

Saya akan menulis makro dengan kursor mulai dari kiri atas. qq4f.dfpq

Lalu saya akan memilih sisa baris menggunakan Vdan menjalankan makro pada baris tersebut dengan:'<,'>norm!@q

Ini hanya akan berfungsi jika format teks tetap sama sehubungan dengan jumlah titik sebelum temp kedua.


5
Untuk membuat makro Anda lebih kuat, Anda harus menggunakan pencarian dan nbukannya 4f.karena jika nama file memiliki lebih banyak titik, makro Anda bisa gagal atau menghapus hal-hal yang tidak boleh dihapus.
statox

1

Tidak ada yang mencegah Anda menggunakan dua regex alih-alih hanya satu, yaitu mengubah kemunculan pertama dan kemudian menukar kolom:

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

Mungkin tidak terlalu pintar tapi saya merasa sangat mudah dibaca.


0

Usaha saya

:%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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.