Hợp nhất các khối bằng các đường xen kẽ


15

Có cách nào chuyên dụng để hợp nhất hai khối văn bản bằng cách xen kẽ các dòng, giống như chuyển từ đây:

a1
a2
a3
a4
  b1
  b2
  b3
  b4

đến đó:

a1
  b1
a2
  b2
a3
  b3
a4
  b4

trong một vài lệnh?

EDIT : Tôi thực sự thích giải pháp của Sato Katsura , đây là cách tôi đã thực hiện nó:

function! Interleave()
    " retrieve last selected area position and size
    let start = line(".")
    execute "normal! gvo\<esc>"
    let end = line(".")
    let [start, end] = sort([start, end], "n")
    let size = (end - start + 1) / 2
    " and interleave!
    for i in range(size - 1)
        execute (start + size + i). 'm' .(start + 2 * i)
    endfor
endfunction

" Select your two contiguous, same-sized blocks, and use it to Interleave ;)
vnoremap <pickYourMap> <esc>:call Interleave()<CR>

Bây giờ tôi tò mò - trường hợp sử dụng của bạn là gì? Bạn có đang đổi tên phụ đề cho một mùa TV không?
VanLaser

@VanLaser Haha, tôi thì không. Hầu hết, tôi đang phân tích cú pháp bằng mắt từ một chương trình, mà tôi cần kiểm tra tính nhất quán liên quan đến thứ tự tạo / sau đó trì hoãn việc đọc các đối tượng. Các khối xen kẽ giúp dễ dàng khớp các dòng tương ứng trong các khối đầu ra bị trì hoãn. Đôi khi tôi cũng cần xen kẽ các dòng mã với các hướng dẫn lặp lại, tương tự để ghi nhật ký hoặc điểm chuẩn. Tạo các hướng dẫn đó thật dễ dàng với các macro, sau đó xen kẽ chúng với mã thực tế giờ chỉ là một vài tổ hợp phím với chức năng này, cảm giác thật tuyệt :)
iago-lito

1
@ lago-lito - cảm ơn câu trả lời! Vâng, Vim khá đa năng :) Biểu hiện "phân tích mắt" của bạn khiến tôi cũng phải suy nghĩ ở scroll-bindinghai cửa sổ Vim.
VanLaser

Tôi gặp sự cố khi sử dụng, bạn chọn hai khối liên tiếp như thế nào? Họ có cần phải liền kề?
cbcoutinho

@cbcoutinho Có họ có :) Tôi không chắc bạn có thể chọn cả hai nếu không. Trong ví dụ tôi đã trình bày, tôi đặt con trỏ lên (giả sử) b1, sau đó tôi nhấn vipđể chọn toàn bộ khối, sau ,itđó là <map-I've-Picked>. Có phải nó không hoạt động về phía bạn?
iago-lito 16/03/18

Câu trả lời:


8

Không có cách chuyên dụng để làm điều đó (theo như tôi biết), nhưng vâng, nó có thể được thực hiện với một vài lệnh:

function! Interleave(start, end, where)
    if a:start < a:where
        for i in range(0, a:end - a:start)
            execute a:start . 'm' . (a:where + i)
        endfor
    else
        for i in range(a:end - a:start, 0, -1)
            execute a:end . 'm' . (a:where + i)
        endfor
    endif
endfunction

Bạn có thể chạy nó với :call Interleave(5, 8, 1). Tham số đầu tiên là dòng đầu tiên để di chuyển, dòng thứ hai là dòng cuối cùng và dòng thứ ba để di chuyển chúng. Bạn có thể muốn bật số dòng để xem những gì bạn đang làm ( :set number).

Điều này giả định các khối không chồng chéo. Xem :help :move:help range()để hiểu làm thế nào các chức năng hoạt động.

Có lẽ có nhiều cách tốt hơn để chọn hai khối. Có một plugin nổi xung quanh được cho là để cho phép bạn trao đổi hai khối. Tôi không thể nhớ tên của plugin, nhưng tác giả (có lẽ là Tiến sĩ Chip nổi tiếng?) Đã suy nghĩ nhiều hơn về việc tìm kiếm một giao diện hơn tôi đã làm. :)


Ngọt! Tôi chỉ cần hai đối số vì hai khối này liền kề nhau và có cùng kích thước: startsize. Với hàm homebrew lấy các giá trị đó từ một lựa chọn, nó sẽ hoàn hảo. Tôi đang giải quyết nó. :)
iago-lito

Crosslink thú vị ? ;)
iago-lito

13

Đây là một thay thế khác:

:g/^a/+4t .
:+,+5d 

Đầu tiên sao chép các dòng có 4 dòng bên dưới vào sau dòng hiện tại ( :h :t) sau đó xóa các dòng b liên tiếp ( :h :d)

Thậm chí tốt hơn là lệnh này:

 :g/^a//^\s*b/m .

Điều đó có nghĩa là, đối với mỗi dòng bắt đầu bằng một dòng tìm tiếp theo bắt đầu bằng 'b' và di chuyển nó xuống bên dưới dòng hiện tại.


1
Tôi đã nhận được "E16: Phạm vi không hợp lệ" trên lệnh thứ hai. Tôi đã cố gắng .+,$dthay thế, và điều đó đã làm việc (như đã làm .+,.+4d).
Peter Lewerin

Không chắc tại sao điều này xảy ra
Christian Brabandt

1
không nó không. Đọc: h: phạm vi, bạn luôn có thể sử dụng đánh số trực tiếp thay vì tìm kiếm regex
Christian Brabandt

2
@ iago-lito Thủ thuật thứ hai luôn hoạt động, nhưng bạn cần đổi /^\s*bsang cách khác :range. ví dụ: chọn khối thứ 1, thực thi'<,'>g/^/'>+1m.
depowsdi

1
@ iago-lito Về cơ bản nó giống như câu trả lời của Christian. Không có gì là mã hóa cứng nếu bạn trực quan chọn khối thứ nhất, '>+1đánh dấu bắt đầu khối thứ hai.
depowsdi

3

Nếu bạn muốn có một chút niềm vui với các macro và đánh dấu, bạn có thể thử một cái gì đó như thế này:

  • Đầu tiên đặt một dấu ấn (ở đây a) trên dòng chứa a1vớima

  • Đi đến dòng chứa b1và đánh dấu nó vớimb

  • Bắt đầu ghi một macro trong thanh ghi bạn muốn (ở đây là thanh ghi q) vớiqq

  • Chèn folowing trong macro của bạn: ddmb'apjma'b

  • Dừng ghi macro với q

  • Chơi nó nhiều lần khi cần thiết với X@qnơi Xlà số thời gian để chơi nó.

Để chi tiết macro:

dd mb 'a p j ma 'b
 |  |  | | |    |
 |  |  | | |    go back to line marked `b`
 |  |  | | |
 |  |  | | move of one line and replace the mark `a`
 |  |  | insert the deleted line under the line marked `a`
 |  |  go to line marked `a`
 |  mark the future line to move with `b`
 delete the line to move

Chỉnh sửa Như lago-lito đã đề cập đến nó trong các bình luận, phương pháp này sẽ ghi đè lên các dấu và bộ đệm.

  • Đối với các nhãn hiệu tôi không nghĩ đó là một vấn đề thực sự: tôi hiếm khi sử dụng tất cả 26 điểm trong bộ đệm và tôi nghĩ rằng hầu hết mọi người sẽ tìm thấy 2 điểm miễn phí.

  • Đối với bộ đệm, có thể lưu nó trong một biến tạm thời: Trước khi ghi lại việc sử dụng macro :let saveReg=getreg('"')để lưu thanh ghi và một khi hành động được thực hiện, sử dụng :call setreg('"', saveReg)để đưa thanh ghi trở về trạng thái trước đó.

Dù sao, tôi phải thừa nhận rằng giải pháp này chỉ là cách giải quyết nhanh và không tối ưu: Theo tôi , câu trả lời của Christan là tốt nhất và nên được chấp nhận vì nó không gây rối với bộ đệm và nhãn hiệu, không bắt buộc người dùng phải tạo một chức năng và cho thấy sức mạnh của lệnh toàn cầu.


Hấp dẫn. Thật không may, điều này ghi đè lên nội dung của nhãn hiệu và sổ đăng ký mà tôi có thể đang sử dụng;)
iago-lito

@ lago-lito: thực sự nó ghi đè lên các dấu và bộ đệm. Đối với nhãn hiệu, tôi không bao giờ sử dụng tất cả 26 điểm trong bộ đệm của mình vì vậy tôi không nghĩ đó thực sự là một vấn đề. Đối với bộ đệm có thể là vấn đề nhiều hơn, tôi nghĩ bạn thường có thể tìm thấy bộ đệm không sử dụng hoặc nếu bạn thực sự không thể, hãy sử dụng một biến tạm thời và các hàm getreg()setreg()để lưu bộ đệm của bạn. Nhưng tôi đồng ý rằng nó không phải là một giải pháp tối ưu :-)
statox

1

Tôi vừa thấy một câu hỏi tương tự khác và giải pháp bao gồm:

Nhảy lên giữa cộng với một:

Mj

Và chạy:

:,$g/./exe 'm' 2*line('.')-line('$')-1

Thật thú vị :) Hãy coi chừng điều này xen kẽ toàn bộ tệp của bạn, và không chỉ đoạn đã chọn!
iago-lito
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.