Sử dụng mẫu của lệnh ex toàn cầu được tìm thấy trên một dòng để thay thế trong một dòng khác


8

Trong mã fortran của tôi, tôi có rất nhiều khối như sau

subroutine name(arg1,arg2,arg3,...)
:
end subroutine

và tôi muốn họ trở thành

subroutine name(arg1,arg2,arg3,...)
:
end subroutine name

Trong đó mỗi khối này có thể được thụt vào bởi bất kỳ số lượng khoảng trắng nào (trên thực tế, các khối đó có thể được lồng vào nhau). Tôi đã thử với lệnh

:g/^ *subroutine \(.*\)/;/end subrout/s/end subroutine/& \1

thay đổi từng dòng (tôi đọc nó ở dòng dưới cùng) không thay đổi gì, giống như bộ đệm \1trống. Lệnh

:g/^ *subroutine \(.*\)/;/end subrout/s/end subroutine/& hello

hoạt động tốt, nhưng rõ ràng không phải là những gì tôi muốn. Vì vậy, câu hỏi là: làm thế nào tôi có thể sử dụng trong chuỗi thay thế một mẫu phù hợp với lệnh ex toàn cầu :g?

EDIT Tôi đang chỉnh sửa câu hỏi vì tại thời điểm tôi đăng nó, tôi vội vàng chấp nhận câu trả lời là câu trả lời cho trường hợp cụ thể mà tôi đã đề cập, nhưng không phải là tiêu đề của câu hỏi, nói chung chung hơn một chút.

Tôi đi đến điểm. Tôi có một tệp như sau (không có ý nghĩa chỉ để làm cho nó chung chung nhất có thể):

# sec1
fun1  are you a function?
fun2 no.
fun3 ok, nice to meet you!

# 2nd part
first line
third line
ops (it was the second)
there were 3 lines in the preceding #

# fourth group
now there's just one
and foreveeer

(Trên thực tế, các dòng theo sau mỗi #dòng là hàng trăm.)

Tôi phải thay thế trong mỗi dòng theo từng #dòng (và trước #dòng sau ); tất cả những sự thay thế này nên sử dụng văn bản sau #dòng đầu (hoặc một phần của nó). Một ví dụ về tôi muốn đạt được là

# sec1
fun1 in sec1  are you a function?
fun2 in sec1 no.
fun3 in sec1 ok, nice to meet you!

# 2nd part
first in 2nd line
third in 2nd line
ops in 2nd (it was the second)
there in 2nd were 3 lines in the preceding #

# fourth group
now in fourth there's just one
and in fourth foreveeer

Lưu ý rằng chỉ từ đầu tiên sau #được chèn vào các dòng sau.

Vì vậy, như tôi đã nói, tôi muốn biết liệu mô hình của :glệnh có thể được sử dụng trong chuỗi thay thế hay không. Tôi rất quan tâm đến câu trả lời này vì rất khó chịu khi đăng ký một macro (một lần nhấn phím sai có nghĩa là bắt đầu lại từ đầu!), Trong khi một lệnh như thế này,

:g/^# \(\<\w\+\>\)/+;/^#/- s/\(\<\w\+\>\)\(.\+$\)/\2 \1 \3

sẽ là hoàn hảo ... Và thật khó để tôi tin rằng không có cách nào để sử dụng một lệnh thực hiện công việc!

Câu trả lời:


4

Bạn có thể sử dụng kết hợp :global, matchit:normal!:

:g/^\s*subroutine/norm ^whye^%$p

Giải trình:

  • :g/^\s*subroutine: cho tất cả các dòng khớp ^\s*subroutine, làm:
  • normal: vào chế độ bình thường (! có nghĩa là không có ánh xạlàm không sử dụng norm!, như !loại bỏ các cuộc gọi đến matchit (nhờ @SatoKatsura))
  • ^đi đến ký tự không trống đầu tiên (không 0, để xử lý các chương trình con lồng nhau)
  • whye: đi đến từ thứ hai (tên), quay lại 1 ký tự (dấu cách) và sao chép nó (khoảng trắng là để làm cho việc dán ở cuối dễ dàng hơn một chút)
  • ^%: quay lại ký tự không trống đầu tiên và sử dụng matchit để tìm kết quả khớp end
  • $p: dán name(với khoảng trắng hàng đầu) ở cuối dòng

2
norm!Giết chết %từ matchit. Giải pháp : :%g/^\s*subroutine/norm ^whye^%$p.
Sato Katsura

À bạn nói đúng. Tôi thực sự đã kiểm tra nó, nhưng tôi đã sử dụng normthay vì norm!, vì tôi khá tự tin rằng tôi không có bất kỳ cài đặt tùy chỉnh nào can thiệp vào đây. Bắt tốt, và cảm ơn vì đã sửa.
Marth

3
@SatoKatsura: Tôi không thấy lý do tại sao bạn cần sử dụng :%g. Tôi đã thử cả hai trên một bộ đệm với các chương trình con riêng biệt và lồng nhau (và với -u NONE) và nhận được kết quả tương tự trong cả hai trường hợp. Mặc dù :globalphạm vi mặc định của tôi là 1,$(tức là %). Trong trường hợp nào sẽ %làm cho một sự khác biệt?
Marth

5

Một cách giải quyết khác có thể là sử dụng macro:

qa/^subroutine<CR>f<space>/end subroutine<CR>$pq

Mà có thể được tách ra như thế này:

qa                  Record a macro in the a register
/^subroutine<CR>    Go to the next occurence of a subroutine declaration
f<space>            Go to the space separating "subroutine" and the name
y$                  Yank till the end of line (i.e. the name)
/end subroutine<CR> Go to the next occurence of "end subroutine"
$p                  Put the name at the end of the line
q                   Stop recording the macro

Sau đó bạn có thể thực hiện macro của bạn với X@anơi Xlà số chương trình con để tiếp tục


1
Chà, tôi sử dụng rất nhiều macro (đăng ký c để bình luận, u để không chú ý, t vào tab, v.v.), vì vậy một macro nữa sẽ không thành vấn đề. Dù sao, quan điểm của tôi là tôi có thể ghi đè macro một cách sai lầm mà không có ý nghĩa gì mà không nhận ra nó (q ở gần w và tôi chưa phải là bậc thầy về gõ phím). Vì vậy, bây giờ, tôi sẽ hy vọng / chờ đợi câu trả lời khác.
Enrico Maria De Angelis

2
Fortran có thể có các chương trình con lồng nhau.
Sato Katsura

4

Đây là giải pháp vĩ mô của @statox , được sửa đổi để đối phó với các tham số chương trình con và chương trình con lồng nhau. Điều này giả sử bạn cũng đã cài đặt matchit :

  • qaq - đăng ký rõ ràng @a
  • qa - bắt đầu ghi vào sổ đăng ký @a
  • /^\s*subroutine\zs<CR>- tìm kiếm subroutine; \zsđể con trỏ trên không gian theo sau nó
  • y2w- gọi tên; 2bởi vì chúng tôi muốn bao gồm không gian, wbởi vì chúng tôi muốn một word(điều này dừng lại ở (v.v.)
  • h - đi bên trái, đến cuối của subroutine
  • %- đi đến kết hợp end subroutine(ba cổ vũ cho matchit)
  • $p - dán tên
  • _ - đi đến ký tự không trống đầu tiên, tức là bắt đầu của (the) end
  • % - quay lại kết hợp subroutine
  • j- xuống, để tìm thêm subroutines
  • 0- đi đến đầu dòng, để không bỏ lỡ a subroutinetrên dòng hiện tại
  • @a - gọi macro hiện tại theo cách đệ quy
  • q - macro kết thúc

Để chạy nó:

  • :set nowrapscan - tránh một vòng lặp vô hạn: macro sẽ bảo lãnh khi nó đến cuối tập tin
  • 1G - đi đến đầu tập tin
  • @a - chạy macro

3

Bạn có thể đi với một lệnh thay thế:

:%s/\v(^subroutine (.+)\_.{-}end subroutine)/\1 \2

Điều này khớp với toàn bộ subroutine / end subroutinetrong nhóm 1 và tên chương trình con trong nhóm 2 và nối chúng.

Đây {-}là một người không tham lam *nên nó sẽ dừng lại ở yếu tố đầu tiên được tìm thấy.

\_.phù hợp với mọi thứ và a new-line.


2
Điều này sẽ không hoạt động, Fortran có thể có các chương trình con lồng nhau.
Sato Katsura

1
Tôi biết, nhưng OP chưa chỉ định bất cứ điều gì về nó. Đề xuất của anh ấy và câu trả lời khác sẽ không hoạt động với các chương trình con lồng nhau. Kết hợp chương trình con "đóng" là một câu hỏi khác hoàn toàn.
nobe4

2
Nó không phải là một vấn đề lớn, matchitcó thể xử lý các chương trình con lồng nhau.
Sato Katsura
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.