Làm thế nào để đảo ngược thứ tự của dòng?


24

Làm cách nào để đảo ngược thứ tự các dòng sao cho dòng đầu tiên xuất hiện ở cuối và dòng cuối cùng xuất hiện trước? (Có thể là tất cả các dòng trong bộ đệm, phạm vi địa chỉ hoặc lựa chọn chế độ trực quan theo chiều dọc.)

Tôi muốn chuyển đổi

rat
ox
tiger
⋮
dog
pig

vào

pig
dog
⋮
tiger
ox
rat

mà không cần dùng đến một lệnh bên ngoài như tac.


Bất kỳ đề xuất cho các thẻ tốt hơn về câu hỏi này?
200_success 22/2/2015

1
có thể là một thẻ 'thuần-vi' mới hoặc tương tự? Tôi đã thấy một số câu hỏi sẽ được hưởng lợi từ một thẻ cho thấy mong muốn không có công cụ bên ngoài liên quan. Tôi có nên hỏi về điều đó trên Meta không?
John O'M.

1
@Carpetsmoker (và bất kỳ ai khác muốn theo dõi điều này) câu hỏi về thẻ hiện có trên meta meta.vi.stackexchange.com/questions/1229/ Lỗi
John O'M.

Câu trả lời:


29

Sức mạnh của toàn cầu sẽ hoạt động ở đây:

:g/^/exe "normal ddggP"

Hoặc, đơn giản hơn (cảm ơn @tommcdo)

:g/^/move 0

Đầu tiên sẽ khớp với mỗi dòng và cho mỗi dòng, xóa nó và dán nó vào đầu tập tin. Khi nó di chuyển qua tập tin, nó đảo ngược văn bản.

Dòng thứ hai tương tự khớp với mọi dòng và di chuyển nó lên trên cùng của tệp.

Lưu ý: Cả hai đều hoạt động trên toàn bộ tệp và sẽ không áp dụng chính xác để đảo ngược một tập hợp con của các dòng. Xem câu trả lời của Ingo Karkat cho một giải pháp hoạt động trong phạm vi.

Sự miêu tả:

glệnh toàn cục
/^/khớp với bất kỳ dòng nào có bắt đầu (tức là tất cả các dòng)
exethực hiện chuỗi sau đây
"normalthực hiện các lệnh chế độ bình thường
ddxóa dòng
ggdi chuyển lên đầu tệp
Pdán trên vị trí hiện tại

move 0 di chuyển dòng hiện tại xuống dưới dòng 0 (đặt nó ở vị trí 1 hoặc dòng đầu tiên của tệp)


6
Thay vì :normallệnh, chúng ta có thể sử dụng lệnh Ex :move 0, để di chuyển dòng đến đầu bộ đệm.
tommcdo

1
Cũng :executechỉ cần thiết khi lệnh cần được xây dựng động, vd :execute 'normal' g:user_command.
tommcdo 22/2/2015

@tommcdo điểm tốt! Tôi có thói quen sử dụng :executevì tôi thường kết thúc việc gắn thêm các lệnh Ex khác sau lệnh hiện có sau đó và nó thuận tiện hơn cho tôi khi đã :execó nó hơn là phải quay lại và chèn nó sau. Thật không may, thói quen đó đã rò rỉ vào câu trả lời này khi nó không được áp dụng nhiều.
John O'M.

1
Giải thích thêm về việc tôi sử dụng :execute: vì nó có một chuỗi, nó cung cấp một phân định rõ ràng về nơi các lệnh chế độ bình thường kết thúc, mặc dù tôi không xây dựng chuỗi, tôi dễ dàng tìm thấy các dấu ngoặc kép cân bằng hơn là tìm kiếm <esc>hoặc bất cứ điều gì để chấm dứt chế độ. Một lần nữa, đây là sở thích và thói quen cá nhân. :-)
John O'M.

3
Điều này sẽ hoạt động cho một phạm vi btw: :9,11g/^/move 8... Số cuối cùng cần là bắt đầu của phạm vi trừ 1 (được điều chỉnh từ câu trả lời của Ingo).
Martin Tournoij

13

Điều này một lót (cho của bạn ~/.vimrc) xác định một :Reverselệnh; bạn cũng có thể sử dụng :globalphần trực tiếp, nhưng cú pháp của :move(mà lần lượt chuyển các dòng thành trước khi bắt đầu phạm vi, do đó đảo ngược nó) không dễ để ghi nhớ:

:command! -bar -range=% Reverse <line1>,<line2>global/^/m<line1>-1

1
Là một FYI cho độc giả, <line1>& <line2>được yêu cầu để thực hiện công việc này trên một phạm vi, tức là: :7,9Reverse(chúng là các tính năng của command, không globalhoặc move). Đơn giản hơn :command! -bar -range=% Reverse :global/^/m 0cũng sẽ hoạt động, nhưng chỉ cho toàn bộ bộ đệm ...
Martin Tournoij

6

Vim tinh khiết:

:g/^/m0

Giải trình:

Theo :help multi-repeat, :gvà anh em họ của nó :vlàm việc theo cách hai chiều.

Vượt qua :gdấu đầu tiên mỗi dòng khớp {pattern}, trong khi vượt qua lần thứ hai (dường như được thực hiện bắt đầu từ đầu tệp và tiến tới cuối) thực hiện [cmd]. Việc sử dụng ở trên :gtận dụng lợi thế của thứ tự các dòng được xử lý (có thể ổn, mặc dù có thể không được đảm bảo về mặt kỹ thuật).

Nó hoạt động bằng cách đánh dấu đầu tiên mỗi dòng, sau đó di chuyển dòng được đánh dấu đầu tiên lên trên cùng của tệp, sau đó di chuyển dòng thứ hai lên trên cùng của tệp (phía trên dòng đã di chuyển trước đó), sau đó là dòng được đánh dấu thứ ba (một lần nữa phía trên dòng đã di chuyển trước đó dòng), và cứ như vậy cho đến khi dòng cuối cùng trong tệp được di chuyển lên trên cùng, đảo ngược tệp một cách hiệu quả.

Lưu ý rằng nếu :gcác dòng được xử lý theo bất kỳ thứ tự nào khác từ trên xuống dưới, lệnh này sẽ không hoạt động.

Nguồn: Đảo ngược tất cả các dòngSức mạnh của g tại vim wikia.

Vài ví dụ sử dụng các lệnh bên ngoài:

  • tac(một phần của lõi GNU - catđảo ngược):

    :%!tac                                                                                                                                                                                                                                                              
    
  • tail trên BSD / OSX (không tuân thủ POSIX):

    :%!tail -r
    

    -r Tùy chọn -r làm cho đầu vào được hiển thị theo thứ tự ngược lại, theo dòng.

    Kiểm tra: man tarđể biết thêm chi tiết.

Để biết thêm ý tưởng, xem:


2
Không :g/^/m0giống như :g/^/move 0, đó là câu trả lời của John?
muru

@muru Tôi nghĩ vậy, nhưng cái này ngắn hơn (theo vim wikia) và tôi đã thêm lời giải thích khác với một vài ví dụ bổ sung về việc sử dụng các dòng lệnh.
kenorb 23/2/2015

Có, tôi đã nâng cấp vì các lệnh khác (tôi cũng đã đăng bài tac). Nhưng tôi nghi ngờ downvote là vì câu trả lời được lặp đi lặp lại.
muru

Tôi biết rằng tacđã được OP đề cập, nhưng tất cả các câu hỏi tương tự khác sẽ được sao chép lại bằng cách này, vì vậy thật tốt khi đề cập lại. John đã lấy cmd này từ nhận xét @tommcdo, ban đầu tôi đã lấy nó từ DerMike , nhưng tôi nghĩ rằng anh ta đã lấy nó đơn giản từ wikia, vì vậy tôi đã đưa ra các khoản tín dụng cho vim wikia, vì vậy nó không hoàn toàn trùng lặp vì cách giải thích hoàn toàn khác nhau.
kenorb 23/2/2015

Nó bổ sung thêm giá trị, vì đây là phiên bản ngắn hơn nhiều với lời giải thích phù hợp và tôi cũng đang ghi có đúng nguồn. Sử dụng lệnh shell rất đơn giản và thuận tiện. Nếu mọi người không đồng ý, họ chỉ có thể bỏ phiếu, không có vấn đề gì lớn.
kenorb 23/2/2015

6

Theo tinh thần của chức năng VimL:

:call setline(1, reverse(getline(1, line('$'))))
  • getline(1, line('$'))trả về một danh sách tất cả các dòng trong bộ đệm. '$'là một đối số đặc biệt line()chỉ ra dòng cuối cùng trong bộ đệm.
  • reverse(...)đảo ngược danh sách đầu vào, tại chỗ. Người ta sẽ cần sử dụng reverse(copy(...))nếu danh sách đầu vào không nên sửa đổi.
  • setline(1, ...)thay thế dòng được chỉ định bằng đối số thứ hai. Khi đối số thứ hai là một danh sách, cùng một số dòng với độ dài của danh sách được thay thế bằng nội dung của danh sách.

Nếu bạn thích, bạn cũng có thể xác định một lệnh có một phạm vi ( %toàn bộ bộ đệm)

:command! -bar -range=% Reverse call setline(<line1>, reverse(getline(<line1>, <line2>)))

1
Tôi thích câu trả lời này. Nó cũng không làm nổi bật nội dung (nếu hlsearchđược bật) như :g/lệnh từ các câu trả lời khác ... Tuy nhiên, hiệu suất có thể kém hơn? Vì nó getline(1, line('$'))nhận được toàn bộ bộ đệm trong bộ nhớ. reverse()dường như được đặt đúng chỗ, do đó sẽ chiếm rất ít bộ nhớ như vậy ...
Martin Tournoij

3

Theo Tài liệu Vim usr_12.txt - Thủ thuật thông minh

12.4 Thứ tự dòng ngược

Các :globallệnh có thể được kết hợp với các :movelệnh để di chuyển tất cả các dòng trước dòng đầu tiên, dẫn đến một tập tin đảo ngược. Lệnh là:

:global/^/m 0

Viết tắt:

:g/^/m 0

Các ^biểu hiện thường xuyên phù hợp với đầu dòng (ngay cả khi dòng là trống). Các :movelệnh di chuyển các dòng phù hợp để sau khi dòng 0 thần thoại, do đó, dòng phù hợp với hiện tại sẽ trở thành dòng đầu tiên của file. Vì :globallệnh không bị nhầm lẫn bởi việc đánh số dòng thay đổi, :globaltiến hành khớp tất cả các dòng còn lại của tệp và đặt từng dòng làm đầu tiên.

Điều này cũng hoạt động trên một loạt các dòng. Đầu tiên di chuyển lên trên dòng đầu tiên và đánh dấu nó với mt. Sau đó di chuyển con trỏ đến dòng cuối cùng trong phạm vi và gõ:

:'t+1,.g/^/m 't

1

Sử dụng số tương đối. Đoạn văn bắt đầu ở dòng 13 và spam thêm 4 dòng

 :13,13+4g/^/m12
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.