VimまたはLinuxでスペースをタブに変換するにはどうすればよいですか?


189

必要なものを見つけることなくスペースをタブに変換する方法について、Stack Overflowでいくつかの質問を見てきました。タブをスペースに変換する方法についてさらに質問があるようですが、私は反対のことをしようとしています。

Vim、私が試した:retab:retab!運なしで、私は信じているものはとにかくスペースにタブから行くために実際にあります。

私は運試しをせずにコマンドプロンプトで両方expandunexpand試しました。

問題のファイルは次のとおりです。

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

またはシェルを使用して、先頭のスペースをタブに変換するにはどうすればよいVimですか?


現在削除されている@Mattのコメントでは、最初の例(sed "s/ +/`echo -e '\t'`/g" < input.py > output.py)は、先頭のスペースだけでなく、すべてのスペースを変換するように表示されます。2番目の例(sed "s/^ +/`echo -e '\t'`/g" < input.py > output.py)では、各行の最初のスペースのみがタブに置き換えられ、残りは残されます。
cwd


すべて/多くのファイルに対する答えが見つからなかったので、自分で作成しました: stackoverflow.com/a/44581474/1115187。そしてブラックジャック(長すぎるが、コメント欄でそれを残すため)findawk
maxkoryukov

回答:


313

Vimを使用してすべての先行スペース(より広い'tabstop')を拡張すると、使用する権利はありましたretabが、最初に'expandtab'リセットされることを確認し:verbose set ts? et?ます(あなたの友達です)。retab範囲を取るため、通常%は「ファイル全体」を意味するように指定します。

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

このようなことをする前に(特にPythonファイルで!)、通常はを設定して'list'、空白を確認して変更できるようにします。

私は、中に次のマッピング持って私の.vimrcこのために:

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

2
ここでは、私は仕事にそれを得た方法ですではないことを確認するものに必要であり、ものではありません、そしてところで私はreatabの前に「%」がやっているのか分からない::set noet:set tabstop=2:retab!:%retab!:set tabstop=1:retab!:%retab!
CWD

2
私が使用する理由についての説明を含めるように、回答を更新しました%F2マッピングは、入力されたとおりです。
Johnsyweb、2012

7
その特定のファイルのために、私はどうなる::set noet ts=2 |%retab!
Johnsyweb

1
@Johnsywebは公平であるために、私は間違っていました::%retab!まだ機能します。私はと混同して==いるなど、ありません preserveindent設定を尊重します。
UNK

1
coffeescriptファイルをスペースからタブに変換するには、@ Johnsywebの回答(.vimrcファイルへの追加を含む)に:set tabstop=4
従い

38

1-スペースがあり、タブが必要な場合。

最初に、1つのタブを持つスペースの数を決定する必要があります。つまり、先頭に4つのスペース、つまり8つの行があるとします。タブを4つのスペースにしたいと思うかもしれません。今その情報で、あなたはします:

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

ここに問題があります!この一連のコマンドは、行頭のスペースだけでなく、すべてのテキストを検索します。それは次のような文字列を意味します:"Hey,␣this␣␣␣␣is␣4␣spaces"になります"Hey,␣this⇥is␣4␣spaces"が、そのありません!そのタブ!

この小さな問題を解決するにはsearch、代わりにをお勧めしますretabます。

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

この検索で​​は、ファイル全体で任意の数のタブで始まり4つのスペースが続く行を探し、見つかったタブの数に1を加えたものに置き換えます。

残念ながら、これはすぐには実行されません。

最初、ファイルにはスペースで始まる行があります。検索では、最初の4つのスペースのみがタブに変換され、次のようになります...

コマンドを繰り返す必要があります。何回?あなたが得るまでpattern not found。プロセスを自動化する方法はまだ考えられません。しかし、そうした場合:

`10@:`

おそらく完了です。このコマンドは、最後の検索/置換を10回繰り返します。あなたのプログラムがそれほど多くのインデントを持つことはおそらくありません。あれば、もう一度繰り返します@@ます。

さて、答えを完成させるために。私はあなたが反対を求めたのを知っています、しかしあなたが物事を元に戻す必要がある時をあなたは決して知りません。

2-タブがあり、スペースが必要です。

まず、タブを変換するスペースの数を決定します。各タブを2つのスペースにしたいとします。次に行います:

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

これは文字列でも同じ問題を抱えています。しかし、文字列内でハードタブを使用しないほうがプログラミングスタイルが優れているため、実際にはここで良いことをしています。文字列内にタブが本当に必要な場合は、を使用してください\t


非常にまれな競合状態のようです。とにかく、視覚的な範囲の選択を受け入れる関数を作成し、一致が見つからなくなるまで検索関数を繰り返します。これは、より賢明で有用な答えになると思います。
albfan 2015

いや、それ。より決定的なソリューションが必要な場合は、関数を使用できます。とにかく、ex commandこれは関数の内部にあるため、での実行方法を知っていることは常に良いことです。そして、それは珍しいことではありません。混乱させるには、スペースを含む文字列が必要です。珍しくありません。私はそこにいます。コメントありがとうございます。
Beco博士、2015

検索を複数回実行する代わりに、/ gで各行の連続するスペースの4のすべてのグループをタブに変換するのに十分ではない理由を説明してください。
Bjartur Thorlacius

こんにちは@BjarturThorlacius、問題は、^シンボルを削除すると、行の先頭から検索を開始すると、文字列内のスペースが変更されるリスクがあることです。では^、あなたはこのように、インデント、行の開始以来、空白文字とタブのみを変更している保証します。あなたは確信している場合はそれに加えて、一度にすべてを行う削除しても大丈夫です^し、1回だけ実行します:%s/\(^I*\)␣␣␣␣/\1^I/g
博士ベコ

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

変換:4つの連続するスペース(=文字の後)のすべてのインスタンスを検索しますが、そのポイントまでの行全体が空白である場合のみです(これは、幅ゼロの後読みアサーションを使用します\@<=)。見つかった各インスタンスをタブ文字に置き換えます。


1
1つのスペース1つのタブに拡張するために機能した唯一のソリューションですが、答えのユニコードに注意してください、私はちょうど使用しました:%s/\(^\s*\)\@<= /\t/g-適切な数のスペース(4つのスペースを1つのタブに変換し、4つのスペースに入れる)を<=
Orwellophile

5

すべてのスペースをタブに変更します:%s / \ s / \ t / g


これがまさに私が必要としていたことです。ありがとう。私がしなければならない唯一の変更は、すべてのスペースを1つにするのではなく、4つのスペースをすべてタブに置き換えることでした。
匿名の人

3

Linux:(unexpandおよびexpand

これは非常に良い解決策です:https : //stackoverflow.com/a/11094620/1115187、これは主に* nix-utilitiesを使用するためです:

  1. unexpand —スペース->タブ
  2. 展開 —タブ->スペース

Linux:カスタムスクリプト

私の元の答え

4つのスペースのインデント({4}スクリプトには2つあります)をフォルダー内のすべての.pyファイルのタブに./app(再帰的に)置き換えるBashスニペット:

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

途中または最後の4つのスペースは変更されません。

Ubuntu 16.0xおよびLinux Mint 18でテスト済み


0

私の場合、タブで置き換える複数のスペース(フィールドは1つ以上のスペースで区切られていました)がありました。次はそれをしました:

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

0

GNU coreutilsがインストールされている場合、%!unexpand --first-onlyまたは4スペースのタブを検討する場合は、%!unexpand -t 4 --first-only--first-onlyを誤って呼び出した場合にunexpand備えて、--all)。

これが唯一の規定のタブ・ストップ、前のスペースを置き換えることに注意してくださいませんそれらに続くスペースを。タブを文字どおりに表示しない限り、vimの視覚的な違いはわかりません。たとえば、次のもの~/.vimrcが含まれますset list listchars=tab:▸┈(これが機能しないと思っunexpandた理由です)。


0

Vimを使用して一連のファイル(たとえば、ディレクトリ階層内のすべての* .tsファイル)を2スペースから4スペースに再タブ化するには、コマンドラインから次のように試すことができます。

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

これはfind、一致するすべてのファイルを渡すために使用していますxargs(findの-print0オプションは、名前にスペースのあるファイルを処理するために、xargsの-0オプションと連動します)。

xargs -eは、実際にはいくつかのコマンドである特定のexコマンドを実行する各ファイルでexモード()でvimを実行し、既存の先行スペースをタブに変更し、タブストップをリセットしてタブをスペースに戻し、最後に保存して終了します。

exモードで実行すると、Vim: Warning: Input is not from a terminalファイルごとにこれを防ぐことができます。


-1

簡単なPythonスクリプト:

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()

1つの大きな問題:このスニペットは、インデント(行の先頭)だけなくすべての 4つのスペースを置き換えます
maxkoryukov

2番目:file-filterは実装されていません
maxkoryukov
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.