Thay thế thứ hai xảy ra trên dòng


12

Tôi có một danh sách các tập tin:

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

Và tôi muốn xóa temp.trên mỗi dòng, nhưng chỉ xuất hiện lần thứ hai , do đó, tệp sẽ trông như sau:

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

Làm thế nào tôi nên làm điều này?


Có thể sẽ có một sự xuất hiện thứ ba hoặc thứ tư trên bất kỳ dòng nào? Những cái này có còn nguyên vẹn không?
James

Trường hợp của tôi là khớp tên tệp cũ với tên tệp mới, vì vậy chỉ có 2 lần xuất hiện trên mỗi dòng. Và chỉ có cái thứ hai nên thay đổi.
nobe4

Câu trả lời:


10

Nói chung, bạn có thể phù hợp với sự xuất hiện thứ N của một cái gì đó bằng cách sử dụng \zs\{N}. Có một ví dụ được đưa ra tại :help \zs.

Trong trường hợp của bạn, lệnh sẽ là:

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

với cờ rất thảm khốc, bạn có thể giảm regex:%s/\v(.{-}\zstemp.){2}//
nobe4

8

Điều này được thực hiện dễ dàng hơn nhiều với sed:

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

Với Vim bạn cần phù hợp với không tham lam, và nó không phải là dễ dàng để mở rộng phương pháp này để thay thế cho 3, 4 vv xảy ra temp. Nhưng nó có thể được thực hiện nếu bạn nhấn mạnh:

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

Cảm ơn bạn đã đưa ra giải pháp sed, bạn có nghĩ rằng có thể áp dụng điều này trên mỗi dòng không?
nobe4

@ nobe4 Không chắc ý của bạn là gì. sedlần lượt áp dụng các kịch bản cho từng dòng đầu vào.
Sato Katsura

có, nhưng bạn có thể chuyển các dòng vào chương trình bên ngoài và lấy lại kết quả.
nobe4

2
Ý bạn là từ Vim? Chắc chắn, bạn có thể đặt các đường ống sedgiống như bạn có thể dẫn chúng đến bất kỳ chương trình nào khác. Fi : :%!sed 's/\.temp\././2'. sedtrong UNIX thân thiện, nó đọc đầu vào từ stdinvà ghi kết quả vào stdout.
Sato Katsura

8

Bạn cũng có thể làm điều này với một cái nhìn.

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

Nếu bạn muốn loại bỏ TẤT CẢ các lần xuất hiện sau lần đầu tiên, bạn có thể nối gcờ ở cuối.

\(\)\@<=Sẽ tìm kiếm bất kỳ mẫu nào giữa \(\)nhưng sẽ không thêm văn bản tìm thấy vào trận đấu.

Xem :h \@<=để biết thêm.


6

Bạn có thể sử dụng macro như @Meshpi đã đề xuất. Nhưng, đây là một cách khác để bạn có thể hoàn thành điều tương tự.

02/temp^Mdwx+

0 - Đi đến đầu của một dòng

2 / temp - Tìm kiếm temp và đi đến lần thứ hai

^ M - Đây chỉ là nhấn phím Enter

dw - xóa từ (temp)

x - xóa '.'

+ - Đi đến đầu dòng tiếp theo

Và, sau đó bạn có thể chỉ cần lặp lại cho đến cuối. Và, sẽ có rất nhiều cách để làm điều tương tự.


6

Giải pháp này tương tự như TessellatingHeckler nhưng dễ dàng thích nghi hơn với bất kỳ mẫu nào phải xóa.

:g/temp\./normal 2ngnd

Đây là cách nó hoạt động:

  1. :g/temp\./ cho mỗi dòng khớp với "temp."
  2. normal thực hiện như sau trong chế độ bình thường
    1. 2n tìm đại lượng thứ hai của mẫu
    2. gn chọn nó
    3. d và xóa nó.

Điều này sẽ làm việc cho bất cứ mô hình nào được đưa ra :g. normalcó thể được viết tắt là norm. gndtương đương với dgn. Chỉnh sửa: Trong thực tế 2ngndlà tương đương vớid2gn .

Xem Wiki Mẹo Vim để biết thêm ví dụ về lệnh toàn cầu.


4

Trong Vim, bạn có thể xác định cột trước / tại / sau đó bạn muốn kết quả khớp với :help \%c:

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

Điều này sẽ loại bỏ mọi thứ .tempđược tìm thấy sau cột 17 của mỗi dòng trong bộ đệm hiện tại.


Lưu ý 1: /g không cần thiết với mẫu của bạn.

Lưu ý 2: Tôi sử dụng tính năng tiện dụng đó rất thường xuyên với qmv . Khuyến nghị!


Neat, tôi đã nghĩ đến việc tạo một plugin, nhưng điều này thật tuyệt!
nobe4

Vim đã làm rất nhiều việc,
romainl 7/07/2016

Chắc chắn, nhưng tôi đã không nhận thức được công cụ này. Và một chút kịch bản luôn luôn vui vẻ!
nobe4

6
@ nobe4 Nếu bạn quan tâm đến những thứ này, hãy xem thêm vidirvipetừ gói moreutils .
Sato Katsura

4

Điều này thực sự khá đơn giản. Để khớp với temp thứ hai, cho phép mọi thứ theo sau là "temp" theo sau bởi bất cứ thứ gì, sau đó tìm lại temp.

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

\zsnghĩa là "Bắt đầu lựa chọn ở đây" để phần đầu tiên của trận đấu (mọi thứ trước temp thứ hai) không bị xóa. Đây thực sự là một tính năng cực kỳ hữu ích mà tôi vừa tìm hiểu! Không có nó, regex sẽ phải như thế này:

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

Nếu có nhiều hơn hai temptrên một dòng, công thức của bạn sẽ xóa cái cuối cùng, thay vì cái thứ hai. Đổ lỗi cho lòng tham. :)
lcd047

2
Vâng, điều này là tham lam, và vì vậy nó xóa cái cuối cùng. Tuy nhiên, OP cho biết 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

Thay vì regex, tôi sẽ thực hiện một lệnh:

  • Nhảy đến cuối dòng
  • Tìm kiếm ngược cho temp
  • Xóa 5 ký tự

và chạy nó trên mọi dòng:

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

Lưu ý ^[là đặc biệt và đại diện nhấn phím Escape; bạn gõ nó bằng:Ctrl-q <Esc>


Nhưng một tùy chọn regex, mà tôi không nghĩ đã được đề xuất, là khớp với temp.bất kỳ thứ gì ngoại trừ a ., được neo vào cuối dòng.

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

Cái nào sẽ khớp temp.txtở cuối dòng và thay thế nó chỉ bằng txtbit.


1

Tôi sẽ viết một macro với con trỏ bắt đầu ở trên cùng bên trái. qq4f.dfpq

Sau đó, tôi sẽ chọn phần còn lại của các dòng bằng cách sử dụng Vvà chạy macro trên các dòng đó với:'<,'>norm!@q

Điều này sẽ chỉ hoạt động nếu định dạng văn bản giữ nguyên liên quan đến số lượng dấu chấm trước temp thứ hai.


5
Để làm cho macro của bạn mạnh mẽ hơn, bạn nên sử dụng một tìm kiếm và nthay 4f.vì bởi vì nếu tên tệp có nhiều dấu chấm hơn, macro của bạn có thể bị lỗi hoặc xóa những thứ không nên xóa.
statox

1

Không có gì ngăn bạn sử dụng hai biểu thức chính thay vì chỉ một, tức là thay đổi lần xuất hiện đầu tiên và sau đó trao đổi các cột:

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

Có thể không thông minh hơn nhưng tôi thấy nó rất dễ đọc.


0

Nỗ lực của tôi

:%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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.