Làm cách nào tôi có thể chuyển đổi không gian sang các tab trong Vim hoặc Linux?


189

Tôi đã xem qua một số câu hỏi về Stack Overflow để biết cách chuyển đổi không gian sang các tab mà không tìm thấy những gì tôi cần. Dường như có nhiều câu hỏi hơn về cách chuyển đổi các tab thành không gian, nhưng tôi đang cố gắng làm điều ngược lại.

Trong Vimtôi đã cố gắng :retab:retab!không gặp may mắn, nhưng tôi tin rằng những điều đó thực sự là để đi từ các tab đến không gian.

Tôi đã thử cả hai expandunexpandtại dấu nhắc lệnh mà không gặp may mắn.

Đây là tập tin trong câu hỏi:

http://gdata-python-client.googlecode.com/hg-history/a9ed9edefd61a0ba0e18c43e448472051821003a/samples/docs/docs_v3_example.py

Làm cách nào tôi có thể chuyển đổi không gian hàng đầu sang các tab bằng cách sử dụng Vimhoặc vỏ?


Trong nhận xét của @ Matt hiện đã bị xóa, ví dụ đầu tiên ( sed "s/ +/`echo -e '\t'`/g" < input.py > output.py) xuất hiện để chuyển đổi tất cả các khoảng trắng, không chỉ các khoảng trắng hàng đầu. Trong ví dụ thứ hai ( sed "s/^ +/`echo -e '\t'`/g" < input.py > output.py) nó chỉ thay thế khoảng trắng đầu tiên trên mỗi dòng bằng một tab và để lại phần còn lại của chúng.
cwd


Tôi không tìm thấy câu trả lời cho tất cả / nhiều tệp , vì vậy tôi đã viết một tệp của riêng mình: stackoverflow.com/a/44581474/1115187 . Tuy nhiên find, với awkvà blackjack (quá lâu để bình luận)
maxkoryukov

Câu trả lời:


313

Sử dụng Vim để mở rộng tất cả các không gian hàng đầu (rộng hơn 'tabstop'), bạn có quyền sử dụng retabnhưng trước tiên hãy đảm bảo 'expandtab'được đặt lại ( :verbose set ts? et?là bạn của bạn). retabmất một phạm vi , vì vậy tôi thường chỉ định %có nghĩa là "toàn bộ tập tin".

:set tabstop=2      " To match the sample file
:set noexpandtab    " Use tabs, not spaces
:%retab!            " Retabulate the whole file

Trước khi làm bất cứ điều gì như thế này (đặc biệt là với các tệp Python!), Tôi thường đặt 'list', để tôi có thể thấy khoảng trắng và thay đổi.

Tôi có các bản đồ sau đây trong tôi.vimrc cho điều này:

nnoremap    <F2> :<C-U>setlocal lcs=tab:>-,trail:-,eol:$ list! list? <CR>

2
dưới đây là cách tôi đã nhận nó để làm việc, không chắc chắn những gì là cần thiết và những gì không phải là, và btw tôi không biết những gì các "%" trước khi reatab đang làm: :set noet, :set tabstop=2, :retab!, :%retab!, :set tabstop=1, :retab!,:%retab!
CWD

2
Tôi đã cập nhật câu trả lời của mình để bao gồm một lời giải thích về lý do tại sao tôi sử dụng %. Ánh xạ F2 chính xác như được gõ .
Johnsyweb

7
Đối với tập tin cụ thể đó, tôi chỉ cần làm::set noet ts=2 |%retab!
Johnsyweb

1
@Johnsyweb để công bằng, tôi đã sai: :%retab!vẫn hoạt động. Tôi đã nhầm lẫn với ==, vv mà không tôn trọng các thiết lập bảo tồn.
Unk

1
Để chuyển đổi tệp coffeescript từ dấu cách sang tab, tôi đã theo dõi câu trả lời của @ Johnsyweb (bao gồm cả bổ sung tệp .vimrc) nhưng thay vào đó bằng:set tabstop=4
Mikeumus

38

1 - Nếu bạn có không gian và muốn các tab.

Đầu tiên, bạn cần quyết định có bao nhiêu khoảng trống sẽ có một tab. Điều đó nói rằng, giả sử bạn có các dòng có 4 khoảng trắng hàng đầu hoặc 8 ... Hơn bạn nhận ra rằng bạn có thể muốn một tab là 4 khoảng trắng. Bây giờ với thông tin đó, bạn làm:

:set ts=4
:set noet
:%retab!

Có một vấn đề ở đây! Chuỗi lệnh này sẽ tìm kiếm tất cả văn bản của bạn, không chỉ khoảng trắng ở đầu dòng. Điều đó có nghĩa là một chuỗi như: "Hey,␣this␣␣␣␣is␣4␣spaces"sẽ trở thành "Hey,␣this⇥is␣4␣spaces", nhưng nó không! đó là một tab!.

Để giải quyết vấn đề nhỏ này, tôi khuyên bạn nên searchthay vì retab.

:%s/^\(^I*\)␣␣␣␣/\1^I/g

Tìm kiếm này sẽ tìm trong toàn bộ tệp cho bất kỳ dòng nào bắt đầu bằng bất kỳ số lượng tab nào, theo sau là 4 khoảng trắng và thay thế nó cho bất kỳ số lượng tab nào nó tìm thấy cộng với một dòng.

Thật không may, điều này sẽ không chạy ngay lập tức!

Lúc đầu, tập tin sẽ có các dòng bắt đầu bằng dấu cách. Sau đó, tìm kiếm sẽ chỉ chuyển đổi 4 khoảng trắng đầu tiên thành một tab và để ...

Bạn cần lặp lại lệnh. Bao nhiêu lần? Cho đến khi bạn nhận được một pattern not found. Tôi không thể nghĩ ra cách nào để tự động hóa quy trình này. Nhưng nếu bạn làm:

`10@:`

Bạn có thể đã hoàn thành. Lệnh này lặp lại lần tìm kiếm / thay thế cuối cùng trong 10 lần. Nó không có khả năng chương trình của bạn sẽ có rất nhiều thụt lề. Nếu có, chỉ cần lặp lại một lần nữa @@.

Bây giờ, chỉ để hoàn thành câu trả lời. Tôi biết bạn đã yêu cầu ngược lại, nhưng bạn không bao giờ biết khi nào bạn cần hoàn tác mọi thứ.

2 - Bạn có các tab và muốn có khoảng trắng.

Đầu tiên, quyết định có bao nhiêu khoảng trống bạn muốn các tab của bạn được chuyển đổi thành. Hãy nói rằng bạn muốn mỗi tab là 2 dấu cách. Sau đó, bạn làm:

:set ts=2
:set et
:%retab!

Điều này sẽ có cùng một vấn đề với chuỗi. Nhưng vì phong cách lập trình tốt hơn của nó để không sử dụng các tab cứng bên trong chuỗi, bạn thực sự đang làm một điều tốt ở đây. Nếu bạn thực sự cần một tab bên trong một chuỗi, sử dụng \t.


Có vẻ là một điều kiện cuộc đua cực kỳ hiếm. Dù sao, tạo một hàm chấp nhận lựa chọn phạm vi hình ảnh và lặp lại chức năng tìm kiếm cho đến khi không tìm thấy kết quả khớp nào, tôi đoán đó sẽ là một câu trả lời thông minh và hữu ích hơn.
albfan

Yeas, hoặc đó. Nếu bạn muốn một giải pháp dứt khoát hơn, bạn có thể sử dụng một chức năng. Dù sao, nó luôn luôn tốt để biết làm thế nào trong ex command, bởi vì đây sẽ là những gì bên trong chức năng. Và không, nó không hiếm. Bạn chỉ cần có các chuỗi có khoảng trắng để có một mớ hỗn độn. Không hiếm chút nào. Tôi đã ở đó. Cảm ơn đã bình luận.
Bác sĩ Beco

Vui lòng giải thích tại sao / g không đủ để chuyển đổi tất cả các nhóm 4 trong mỗi dòng khoảng trắng thành các tab, thay vì phải chạy tìm kiếm nhiều lần.
Bjartur Thorlacius

Xin chào @BjarturThorlacius, vấn đề là nếu bạn xóa ^biểu tượng, để bắt đầu tìm kiếm từ đầu dòng, bạn có nguy cơ thay đổi khoảng trắng bên trong chuỗi. Do đó, ^bạn đảm bảo rằng bạn chỉ thay đổi khoảng trắng và tab kể từ khi bắt đầu dòng, do đó, thụt lề. Bên cạnh đó, nếu bạn chắc chắn có thể làm tất cả cùng một lúc, hãy xóa ^và chỉ chạy một lần với::%s/\(^I*\)␣␣␣␣/\1^I/g
Dr Beco

14
:%s/\(^\s*\)\@<=    /\t/g

Dịch: Tìm kiếm mọi trường hợp của 4 khoảng trắng liên tiếp (sau ký tự =), nhưng chỉ khi toàn bộ dòng đến thời điểm đó là khoảng trắng (điều này sử dụng xác nhận nhìn phía sau độ rộng bằng không, \@<=). Thay thế mỗi trường hợp tìm thấy bằng một ký tự tab.


1
Tôi chỉ sử dụng giải pháp duy nhất để mở rộng 1 khoảng trắng thành 1 tab , nhưng hãy cẩn thận với unicode trong câu trả lời, tôi chỉ sử dụng :%s/\(^\s*\)\@<= /\t/g- đặt số lượng khoảng trắng thích hợp (để chuyển đổi 4 khoảng trắng thành 1 tab, đặt vào 4 khoảng trắng) ngay sau<=
Orwellophile

5

Thay đổi tất cả khoảng trắng thành tab:% s / \ s / \ t / g


Đây chính xác là những gì tôi cần. Cảm ơn. Thay đổi duy nhất tôi phải thực hiện là thay thế mỗi 4 khoảng trắng bằng một tab thay vì thực hiện mọi khoảng trống.
Người ẩn danh

3

Linux: với unexpand(và expand)

Đây là một giải pháp rất tốt: https://stackoverflow.com/a/11094620/1115187 , chủ yếu là vì nó sử dụng * nix-tiện ích:

  1. chưa mở rộng - dấu cách -> tab
  2. mở rộng - tab -> dấu cách

Linux: tập lệnh tùy chỉnh

Câu trả lời ban đầu của tôi

Đoạn trích Bash để thay thế thụt lề 4 không gian (có hai đoạn {4}mã) bằng các tab trong tất cả .pycác tệp trong ./appthư mục (đệ quy):

find ./app -iname '*.py' -type f \
    -exec awk -i inplace \
    '{ match($0, /^(( {4})*)(.*?)$/, arr); gsub(/ {4}/, "\t", arr[1]) }; { print arr[1] arr[3] }' {} \; 

Nó không sửa đổi 4 khoảng trắng ở giữa hoặc ở cuối.

Đã được thử nghiệm trong Ubuntu 16.0x và Linux Mint 18


0

Trong trường hợp của tôi, tôi có nhiều khoảng trắng (các trường được phân tách bằng một hoặc nhiều khoảng trắng) mà tôi muốn thay thế bằng một tab. Sau đây đã làm điều đó:

:% s/\s\+/\t/g

0

Nếu bạn đã cài đặt GNU coreutils, hãy xem xét %!unexpand --first-onlyhoặc cho các tab 4 không gian, hãy xem xét %!unexpand -t 4 --first-only( --first-onlycó mặt chỉ trong trường hợp bạn vô tình gọi unexpandvới --all).

Lưu ý rằng điều này sẽ chỉ thay thế các khoảng trắng trước các điểm dừng theo quy định, chứ không phải các khoảng trắng theo sau chúng; bạn sẽ không thấy sự khác biệt về hình ảnh trong vim trừ khi bạn hiển thị các tab theo nghĩa đen hơn; ví dụ: ~/.vimrcchứa của tôi set list listchars=tab:▸┈(tôi nghi ngờ đây là lý do tại sao bạn nghĩ rằng unexpandnó không hoạt động).


0

Để sử dụng Vim để truy xuất một tập hợp các tệp (ví dụ: tất cả các tệp * .ts trong phân cấp thư mục) từ nói 2 khoảng trắng đến 4 khoảng trắng, bạn có thể thử điều này từ dòng lệnh:

find . -name '*.ts' -print0 | xargs -0 -n1 vim -e '+set ts=2 noet | retab! | set ts=4 et | retab | wq'

Điều này đang làm là sử dụng findđể chuyển tất cả các tệp phù hợp tới xargs(tùy chọn -print0 trên find hoạt động với tùy chọn -0 cho xargs để xử lý các tệp w / khoảng trắng trong tên).

xargs chạy vim trong chế độ ex ( -e) trên mỗi tệp thực thi lệnh ex đã cho thực sự là một số lệnh, để thay đổi khoảng trắng hàng đầu hiện có thành tab, đặt lại điểm dừng tab và thay đổi tab trở lại khoảng trắng và cuối cùng lưu và thoát.

Chạy trong chế độ ex ngăn điều này: Vim: Warning: Input is not from a terminalcho mỗi tệp.


-1

Tập lệnh Python đơn giản:

import os

SOURCE_ROOT = "ROOT DIRECTORY - WILL CONVERT ALL UNDERNEATH"

for root, dirs, files in os.walk(SOURCE_ROOT):
    for f in files:
        fpath = os.path.join(root,f)
        assert os.path.exists(fpath)
        data = open(fpath, "r").read()
        data = data.replace("    ", "\t")
        outfile = open(fpath, "w")
        outfile.write(data)
        outfile.close()

Một vấn đề lớn: đoạn trích này thay thế tất cả 4 khoảng trắng, không chỉ thụt lề (ở đầu dòng)
maxkoryukov

và thứ hai: bộ lọc tệp không được triển khai
maxkoryukov
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.