Как я могу преобразовать пробелы в табуляции в Vim или Linux?

192

Я просмотрел несколько вопросов о переполнении стека, чтобы узнать, как преобразовать пробелы во вкладки, не найдя того, что мне нужно. Кажется, есть еще вопросы о том, как преобразовать табуляции в пробелы, но я пытаюсь сделать наоборот.

В VimЯ пытался :retabи :retab!без везения, но я считаю , те , на самом деле для перехода из вкладок пространства в любом случае.

Я попробовал оба expandи unexpandв командной строке без какой-либо удачи.

Вот этот файл:

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

Как я могу преобразовать начальные пробелы во вкладки, используя либо Vimоболочку?

УХО
источник
В комментарии @ Matt, который теперь удален, первый example ( sed "s/ +/`echo -e '\t'`/g" < input.py > output.py) отображает все пробелы, а не только начальные пробелы. Во втором примере ( sed "s/^ +/`echo -e '\t'`/g" < input.py > output.py) он заменяет только первый пробел в каждой строке на вкладку и оставляет остальные из них.
cwd
Противоположный связан: Как заменить табуляцию пробелами? на Vim SE
kenorb
Я не нашел ответа для всех / многих файлов , поэтому я написал свой собственный: stackoverflow.com/a/44581474/1115187 . С find, awkи блэкджек (слишком долго , чтобы оставить его в комментариях, хотя)
maxkoryukov

Ответы:

316

Используя 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>
Johnsyweb
источник
2
вот как я получил его на работу, не уверен , что нужно , а что нет, и кстати я не знаю , что такое «%» перед reatab делает: :set noet, :set tabstop=2, :retab!, :%retab!, :set tabstop=1, :retab!,:%retab!
УХО
2
Я обновил свой ответ, чтобы включить объяснение, почему я использую %. Отображение F2 точно так, как оно напечатано .
Johnsyweb
7
Для этого конкретного файла я бы просто сделал::set noet ts=2 |%retab!
Johnsyweb
1
@Johnsyweb, если честно, я был неправ: :%retab!все еще работает. Я был смущен ==, и т. Д., Который действительно уважает установку preservindent.
Unk
1
Чтобы преобразовать файл coffeescript из пробелов во вкладки, я следовал за ответом @ Johnsyweb (включая добавление к файлу .vimrc), но вместо этого:set tabstop=4
Mikeumus
38

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 пробела, и заменять его на любое количество найденных вкладок плюс одну.

Это, к сожалению, не запустится сразу!

Сначала файл будет иметь строки, начинающиеся с пробелов. Затем поиск преобразует только первые 4 пробела в табуляцию, и позволяет следующее ...

Вам нужно повторить команду. Сколько раз? Пока не получишь pattern not found. Я пока не могу придумать, как автоматизировать процесс. Но если вы делаете:

`10@:`

Вы, вероятно, сделали. Эта команда повторяет последний поиск / замену 10 раз. Вряд ли в вашей программе будет так много отступов. Если это так, просто повторите еще раз @@.

Теперь просто для завершения ответа. Я знаю, что вы просили об обратном, но никогда не знаете, когда вам нужно что-то отменить.

2 - У вас есть вкладки и вы хотите пробелы.

Во-первых, решите, во сколько мест вы хотите конвертировать ваши вкладки. Допустим, вы хотите, чтобы каждая вкладка была 2 пробела. Затем вы делаете:

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

Это будет иметь ту же проблему со строками. Но так как это лучший стиль программирования, позволяющий не использовать жесткие вкладки внутри строк, вы на самом деле делаете здесь что-то хорошее. Если вам действительно нужна вкладка внутри строки, используйте \t.

Доктор Беко
источник
Кажется, крайне редкое состояние гонки. В любом случае, создайте функцию, принимающую выбор из визуального диапазона, и выполняйте итерацию до тех пор, пока совпадение не будет найдено, я думаю, это будет более умный и полезный ответ.
Альбфан
Да, или что. Если вы хотите более точное решение, вы можете использовать функцию. В любом случае, всегда полезно знать, как это сделать ex command, потому что это будет то, что находится внутри функции. И нет, это не редкость. Вам просто нужно иметь строки с пробелами, чтобы иметь беспорядок. Не редкость вообще. Я был там. Спасибо за комментарий.
Доктор Беко
Пожалуйста, объясните, почему / g недостаточно для преобразования всех групп по 4 в каждой строке подряд в одну строку вместо необходимости выполнять поиск несколько раз.
Бьяртур Торлаций
Привет @BjarturThorlacius, проблема в том, что если вы удалите ^символ, чтобы начать поиск с начала строки, вы рискуете изменить пробелы внутри строк. С ^гарантией вы меняете только пробелы и табуляции с начала строки, таким образом, отступ. Кроме того, если вы уверены, что все в порядке, снимите ^и запустите только один раз::%s/\(^I*\)␣␣␣␣/\1^I/g
Dr Beco
15
:%s/\(^\s*\)\@<=    /\t/g

Перевод: Поиск для каждого экземпляра 4 последовательных пробелов (после символа =), но только в том случае, если вся строка до этой точки является пробелом (при этом используется обратное утверждение нулевой ширины, \@<=). Замените каждый найденный экземпляр символом табуляции.

Саймон Цукербраун
источник
1
Единственное решение, которое работало для расширения 1 пробела до 1 табуляции , но остерегайтесь Unicode в ответе, который я только что использовал :%s/\(^\s*\)\@<= /\t/g- поставить соответствующее количество пробелов (чтобы преобразовать 4 пробела в 1 таб, поместить в 4 пробела) сразу после<=
Orwellophile
5

Изменяет все пробелы на табуляцию:% s / \ s / \ t / g

Мурат Будак
источник
Это именно то, что мне было нужно. Спасибо. Единственное изменение, которое я должен был сделать, это заменить каждые 4 пробела на табуляцию вместо того, чтобы делать каждый пробел.
Аноним
3

Linux: с unexpandexpand)

Вот очень хорошее решение: 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

maxkoryukov
источник
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(опция -print0 в find работает с опцией -0 для xargs для обработки файлов с пробелами в имени).

xargs запускает vim в ex mode ( -e) для каждого файла, выполняя данную ex-команду, которая на самом деле состоит из нескольких команд, чтобы заменить существующие начальные пробелы на табуляцию, сбросить табуляцию табуляции и вернуть вкладки обратно на пробелы и, наконец, сохранить и выйти.

Запуск в режиме ex предотвращает это: Vim: Warning: Input is not from a terminalдля каждого файла.

Майк Липперт
источник
-1

Простой Python Script:

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
и второе: файл-фильтр не реализован
макскорюков