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


190

我已经查看了有关Stack Overflow的几个问题,以了解如何在不查找所需内容的情况下将空格转换为制表符。关于如何将制表符转换为空格,似乎还有更多问题,但我正尝试相反的做法。

Vim我尝试过的过程中:retab:retab!没有运气,但我相信这些实际上是为了从制表符转到空格。

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

这是有问题的文件:

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

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


在@Matt现在删除的注释中,第一个示例(sed "s/ +/`echo -e '\t'`/g" < input.py > output.py)似乎是转换所有空格,而不仅仅是前导空格。在第二个示例(sed "s/^ +/`echo -e '\t'`/g" < input.py > output.py)中,它仅用制表符替换每行的第一个空格,并保留其余的行。
2012年

对面相关:如何用空格替换制表符?在Vim SE
kenorb

我找不到所有/许多文件的答案,所以我写了自己的一个文件: stackoverflow.com/a/44581474/1115187。随着findawk和二十一点(太长,把它留在评论,虽然)
maxkoryukov

Answers:


314

使用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

在进行此类操作(尤其是使用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

7
对于该特定文件,我将要做::set noet ts=2 |%retab!
Johnsyweb'2

1
@Johnsyweb说句公道话,我错了::%retab!仍然有效。我与混淆==,等等,它确实遵守了keepindent设置。
Unk 2012年

1
要将咖啡脚本文件从空格转换为选项卡,我遵循了@Johnsyweb的回答(包括对.vimrc文件的添加),但改用:set tabstop=4
Mikeumus

38

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

首先,您需要确定一个标签中有多少空格。就是说,假设您的行首4个空格,即8个。现在,有了该信息,您可以:

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

这里有问题!此命令序列将查找您的所有文本,而不仅仅是行首。那意味着一个字符串,如:"Hey,␣this␣␣␣␣is␣4␣spaces"将变为"Hey,␣this⇥is␣4␣spaces",但不是!它的一个标签!

为了解决这个小问题,我建议使用a search代替retab

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

此搜索将在整个文件中查找任何行,这些行以任意数量的选项卡开头,后跟4个空格,并用找到的任意数量的选项卡加一个代替。

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

首先,文件将包含以空格开头的行。然后,搜索将仅将前4个空格转换为选项卡,并让以下内容...

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

`10@:`

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

现在,只需完成答案即可。我知道您要求相反,但您永远不知道何时需要撤消操作。

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

首先,确定要将选项卡转换为多少空格。假设您希望每个标签为2个空格。然后执行以下操作:

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

字符串也会有同样的问题。但是,由于它的更好的编程风格是不在字符串中使用硬标签,因此您实际上在这里做得很好。如果您确实需要在字符串内使用制表符,请使用\t


似乎是极为罕见的比赛条件。无论如何,创建一个接受可视范围选择的功能并迭代搜索功能,直到找不到匹配项,我猜这将是一个更聪明和有用的答案。
albfan

是的,或者那样。如果需要更确定的解决方案,可以使用函数。无论如何,总是很高兴知道如何在中进行操作ex command,因为这将是函数内部的内容。不,它并不罕见。您只需要使用带空格的字符串就可以避免混乱。一点也不罕见。我去过那里 感谢您的评论。
Beco博士

请解释为什么/ g不足以将每行连续空格中的所有4组转换为制表符,而不必多次运行搜索。
Bjartur Thorlacius

@BjarturThorlacius,您好,问题是,如果删除该^符号,要从该行的开头开始搜索,则可能会更改字符串中的空格。使用,^可以保证自行开始以来仅更改空格和制表符,因此缩进。除此之外,如果您确定可以一次完成所有操作,请删除^并仅运行一次::%s/\(^I*\)␣␣␣␣/\1^I/g
Beco博士

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

翻译:搜索4个连续空格的每个实例(在=字符之后),但仅当到达该点的整行是空格(使用零宽度后向断言,\@<=)时才进行搜索。用制表符替换每个找到的实例。


1
唯一可以将1个空格扩展到1个标签的解决方案,但是要当心答案中的unicode,我只是使用了:%s/\(^\s*\)\@<= /\t/g-在<=
Orwellophile

5

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


这正是我所需要的。谢谢。我唯一要做的更改是用制表符代替每4个空格,而不是每个空格。
匿名人士

3

Linux:带有unexpand(和expand

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

  1. 展开 -空格->选项卡
  2. 展开 -标签->空格

Linux:自定义脚本

我的原始答案

Bash片段,用文件夹中所有文件中的选项卡(递归)替换4个空格的缩进({4}脚本中有两个):.py./app

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

就我而言,我有多个空格(字段被一个或多个空格分隔),我想用制表符替换。做到了以下几点:

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

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

一个巨大的问题:此代码段取代了所有 4个空格,而不仅仅是缩进(在行首)
maxkoryukov

第二个:未实现文件过滤器
maxkoryukov
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.