如何在 Vim 或 Linux 中将空格转换为制表符?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9104706/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 04:19:33  来源:igfitidea点击:

How can I convert spaces to tabs in Vim or Linux?

linuxvimtabsspaces

提问by cwd

I've looked over several questions on Stack Overflow for how to convert spaces to tabs without finding what I need. There seem to be more questions about how to convert tabs to spaces, but I'm trying to do the opposite.

我在 Stack Overflow 上查看了几个关于如何将空格转换为制表符而没有找到我需要的问题的问题。关于如何将制表符转换为空格似乎还有更多问题,但我正试图做相反的事情。

In VimI've tried :retaband :retab!without luck, but I believe those are actually for going from tabs to spaces anyways.

Vim我试过:retab:retab!没有运气,但我相信那些实际上是从标签反正要空间。

I tried both expandand unexpandat the command prompt without any luck.

我在命令提示符下都尝试了expandunexpand但没有任何运气。

Here is the file in question:

这是有问题的文件:

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

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

How can I convert leadingspaces to tabs using either Vimor the shell?

如何使用或 shell将前导空格转换为制表符Vim

采纳答案by Johnsyweb

Using Vim to expand all leadingspaces (wider than 'tabstop'), you were right to use retabbut first ensure 'expandtab'is reset (:verbose set ts? et?is your friend). retabtakes a range, so I usually specify %to mean "the whole file".

使用 Vim 扩展所有前导空格(大于'tabstop'),您可以正确使用,retab但首先确保'expandtab'已重置(:verbose set ts? et?是您的朋友)。retab需要一个range,所以我通常指定%表示“整个文件”。

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

Before doing anything like this (particularly with Python files!), I usually set 'list', so that I can seethe whitespace and change.

在做这样的事情之前(尤其是 Python 文件!),我通常会设置'list',这样我就可以看到空格并进行更改。

I have the following mapping in my .vimrcfor this:

我在下面的映射.vimrc这个:

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

回答by Dr Beco

1- If you have spaces and want tabs.

1- 如果您有空格并需要制表符。

First, you need to decide how many spaces will have a single tab. That said, suppose you have lines with leading 4 spaces, or 8... Than you realize you probably want a tab to be 4 spaces. Now with that info, you do:

首先,您需要确定单个制表符有多少个空格。也就是说,假设您有 4 个空格或 8 个前导的行...然后您意识到您可能希望制表符为 4 个空格。现在有了这些信息,你可以:

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

There is a problem here! This sequence of commands will look for all your text, not only spaces in the begin of the line. That mean a string like: "Hey,?this????is?4?spaces"will become "Hey,?this?is?4?spaces", but its not! its a tab!.

这里有问题!这一系列命令将查找您的所有文本,而不仅仅是行首的空格。这意味着像这样的字符串:"Hey,?this????is?4?spaces"will be "Hey,?this?is?4?spaces",但不是!它是一个标签!。

To settle this little problem I recomend a search, instead of retab.

为了解决这个小问题,我建议使用search, 而不是retab

:%s/^\(^I*\)????/^I/g

This search will look in the whole file for any lines starting with whatever number of tabs, followed by 4 spaces, and substitute it for whatever number of tabs it found plus one.

此搜索将在整个文件中查找以任意数量的制表符开头的任何行,后跟 4 个空格,并将其替换为找到的任意数量的制表符加 1。

This, unfortunately, will not run at once!

不幸的是,这不会立即运行!

At first, the file will have lines starting with spaces. The search will then convert only the first 4 spaces to a tab, and let the following...

起初,文件会有以空格开头的行。然后搜索将仅将前 4 个空格转换为制表符,并让以下...

You need to repeat the command. How many times? Until you get a pattern not found. I cannot think of a way to automatize the process yet. But if you do:

您需要重复该命令。多少次?直到你得到一个pattern not found. 我还想不出一种方法来自动化这个过程。但如果你这样做:

`10@:`

You are probably done. This command repeats the last search/replace for 10 times. Its not likely your program will have so many indents. If it has, just repeat again @@.

你可能已经完成了。此命令重复上次搜索/替换 10 次。您的程序不太可能有这么多缩进。如果有,就再重复一遍@@

Now, just to complete the answer. I know you asked for the opposite, but you never know when you need to undo things.

现在,只是为了完成答案。我知道你的要求正好相反,但你永远不知道什么时候需要撤消。

2- You have tabs and want spaces.

2- 您有制表符并需要空格。

First, decide how many spaces you want your tabs to be converted to. Lets say you want each tab to be 2 spaces. You then do:

首先,确定您希望将制表符转换为多少个空格。假设您希望每个制表符为 2 个空格。然后你做:

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

This would have the same problem with strings. But as its better programming style to not use hard tabs inside strings, you actually are doing a good thing here. If you really need a tab inside a string, use \t.

这对字符串会有同样的问题。但是作为更好的编程风格,不在字符串中使用硬制表符,你实际上在这里做得很好。如果您确实需要字符串中的制表符,请使用\t.

回答by Simon Zuckerbraun

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

Translation: Search for every instance of 4 consecutive spaces (after the = character), but only if the entire line up to that point is whitespace (this uses the zero-width look-behind assertion, \@<=). Replace each found instance with a tab character.

翻译:搜索 4 个连续空格的每个实例(在 = 字符之后),但前提是到该点的整行都是空格(这使用零宽度后视断言,\@<=)。用制表符替换每个找到的实例。

回答by Michael W.

Simple Python Script:

简单的 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()

回答by maxkoryukov

Linux: with unexpand(and expand)

Linux:与unexpand(和expand

Here is a very good solution: https://stackoverflow.com/a/11094620/1115187, mostly because it uses *nix-utilities:

这是一个非常好的解决方案:https: //stackoverflow.com/a/11094620/1115187,主要是因为它使用*nix-utilities:

  1. unexpand— spaces -> tabs
  2. expand— tabs -> spaces
  1. unexpand— 空格 -> 制表符
  2. 展开— 制表符 -> 空格

Linux: custom script

Linux:自定义脚本

My original answer

我的原答案

Bash snippet for replacing 4-spaces indentation (there are two {4}in script) with tabs in all .pyfiles in the ./appfolder (recursively):

用于在文件夹中的所有文件中用制表符替换4 个空格缩进({4}脚本中有两个)的Bash 片段(递归):.py./app

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

It doesn't modify 4-spaces in the middle or at the end.

它不会修改中间或末尾的 4 个空格。

Was tested under Ubuntu 16.0x and Linux Mint 18

在 Ubuntu 16.0x 和 Linux Mint 18 下测试

回答by murat budak

Changes all spaces to tab :%s/\s/\t/g

将所有空格更改为制表符 :%s/\s/\t/g

回答by zee

In my case, I had multiple spaces(fields were separated by one or more space) that I wanted to replace with a tab. The following did it:

就我而言,我有多个空格(字段由一个或多个空格分隔),我想用制表符替换它们。以下是这样做的:

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

回答by Adam Katz

If you have GNU coreutils installed, consider %!unexpand --first-onlyor for 4-space tabs, consider %!unexpand -t 4 --first-only(--first-onlyis present just in case you were accidentally invoking unexpandwith --all).

如果您已经安装GNU的coreutils,考虑%!unexpand --first-only或4维空间中的选项卡,可以考虑%!unexpand -t 4 --first-only--first-only存在以防万一你偶然地被调用unexpand--all)。

Note that this will only replace the spaces preceding the prescribed tab stops, notthe spaces that follow them; you will see no visual difference in vim unless you display tabs more literally; for example, my ~/.vimrccontains set list listchars=tab:?┈(I suspect this is why you thought unexpanddidn't work).

请注意,这只会替换规定的制表位之前的空格,而不是它们后面的空格;除非您更字面地显示选项卡,否则您不会在 vim 中看到任何视觉差异;例如,我的~/.vimrc包含set list listchars=tab:?┈(我怀疑这就是您认为unexpand不起作用的原因)。

回答by Mike Lippert

To use Vim to retab a set of files (e.g. all the *.ts files in a directory hierarchy) from say 2 spaces to 4 spaces you can try this from the command line:

要使用 Vim 将一组文件(例如目录层次结构中的所有 *.ts 文件)从 2 个空格重新设置为 4 个空格,您可以从命令行尝试:

##代码##

What this is doing is using findto pass all the matching files to xargs(the -print0 option on find works with the -0 option to xargs in order to handle files w/ spaces in the name).

这样做是find用来将所有匹配的文件传递给xargs( find 上的 -print0 选项与 xargs 的 -0 选项一起使用,以便处理名称中带有空格的文件)。

xargs runs vim in ex mode (-e) on each file executing the given ex command which is actually several commands, to change the existing leading spaces to tabs, resetting the tab stop and changing the tabs back to spaces and finally saving and exiting.

xargs 在-e执行给定 ex 命令(实际上是几个命令)的每个文件上以 ex 模式 ( )运行 vim,将现有的前导空格更改为制表符,重置制表位并将制表符更改回空格,最后保存并退出。

Running in ex mode prevents this: Vim: Warning: Input is not from a terminalfor each file.

在 ex 模式下运行可以防止这种情况:Vim: Warning: Input is not from a terminal对于每个文件。