Come posso convertire gli spazi in schede in Vim o Linux?


192

Ho esaminato diverse domande su Stack Overflow per come convertire gli spazi in schede senza trovare quello che mi serve. Sembra che ci siano più domande su come convertire le schede in spazi, ma sto cercando di fare il contrario.

In Vimci ho provato :retabe :retab!senza fortuna, ma credo che quelli siano effettivamente per passare dalle schede agli spazi comunque.

Ho provato entrambi expande unexpandal prompt dei comandi senza fortuna.

Ecco il file in questione:

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

Come posso convertire portano gli spazi per le schede utilizzando sia Vimo la conchiglia?


Nel commento di @ Matt che ora è stato eliminato, il primo esempio ( sed "s/ +/`echo -e '\t'`/g" < input.py > output.py) sembra convertire tutti gli spazi, non solo gli spazi iniziali. Nel secondo esempio ( sed "s/^ +/`echo -e '\t'`/g" < input.py > output.py) sostituisce solo il primo spazio su ogni riga con una scheda e ne lascia il resto.
Cwd


Non ho trovato la risposta per tutti / molti file , quindi ho scritto il mio: stackoverflow.com/a/44581474/1115187 . Con find, awke blackjack (troppo lungo per lasciare nei commenti, però)
maxkoryukov

Risposte:


316

Utilizzando Vim per espandere tutti i principali spazi (più larga 'tabstop'), hai fatto bene a uso retab, ma prima assicurarsi 'expandtab'viene azzerata ( :verbose set ts? et?è tuo amico). retabprende un intervallo , quindi di solito specifico %per indicare "l'intero file".

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

Prima di fare qualcosa del genere (in particolare con i file Python!), Di solito imposto 'list', in modo da poter vedere lo spazio bianco e cambiare.

Ho il seguente mapping nel mio.vimrc per questo:

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

2
ecco come ho ottenuto il lavoro, non so cosa è necessario e cosa non lo è, e btw io non so quale sia la "%" prima reatab sta facendo: :set noet, :set tabstop=2, :retab!, :%retab!, :set tabstop=1, :retab!,:%retab!
CWD

2
Ho aggiornato la mia risposta per includere una spiegazione sul perché utilizzo %. La mappatura F2 è esattamente come è stata digitata .
Johnsyweb,

7
Per quel particolare file, farei semplicemente::set noet ts=2 |%retab!
Johnsyweb il

1
@Johnsyweb per essere onesti, ho sbagliato: :%retab!funziona ancora. Ero confuso con ==, ecc, che fa rispettare l'impostazione preserveindent.
Sconosciuto il

1
Per convertire un file coffeescript da spazi a schede ho seguito la risposta di @ Johnsyweb (inclusa l'aggiunta al file .vimrc) ma invece con un:set tabstop=4
Mikeumus,

38

1 - Se hai spazi e vuoi schede.

Innanzitutto, devi decidere quanti spazi avranno una singola scheda. Detto questo, supponiamo di avere linee con 4 spazi iniziali, o 8 ... Di quanto ti rendi conto che probabilmente vuoi che una scheda sia di 4 spazi. Ora con queste informazioni, fai:

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

C'è un problema qui! Questa sequenza di comandi cercherà tutto il testo, non solo gli spazi all'inizio della riga. Ciò significa che una stringa come: "Hey,␣this␣␣␣␣is␣4␣spaces"diventerà "Hey,␣this⇥is␣4␣spaces", ma non lo è! è una scheda !.

Per risolvere questo piccolo problema, raccomando a search, invece di retab.

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

Questa ricerca cercherà nell'intero file tutte le righe che iniziano con qualsiasi numero di schede, seguite da 4 spazi e lo sostituiranno con qualsiasi numero di schede trovate più una.

Questo, sfortunatamente, non funzionerà subito!

Inizialmente, il file avrà linee che iniziano con spazi. La ricerca convertirà quindi solo i primi 4 spazi in una scheda e consentirà quanto segue ...

Devi ripetere il comando. Quante volte? Fino a quando non ottieni un pattern not found. Non riesco ancora a pensare a un modo per automatizzare il processo. Ma se lo fai:

`10@:`

Probabilmente hai finito. Questo comando ripete l'ultima ricerca / sostituzione per 10 volte. Non è probabile che il tuo programma abbia così tanti rientri. In tal caso, ripeti di nuovo @@.

Ora, solo per completare la risposta. So che hai chiesto il contrario, ma non sai mai quando devi annullare le cose.

2 - Hai schede e desideri spazi.

Innanzitutto, decidi in quanti spazi vuoi convertire le tue schede. Diciamo che vuoi che ogni scheda sia di 2 spazi. Quindi fai:

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

Ciò avrebbe lo stesso problema con le stringhe. Ma dato che è il suo migliore stile di programmazione per non usare schede rigide all'interno delle stringhe, in realtà stai facendo una buona cosa qui. Se hai davvero bisogno di una scheda all'interno di una stringa, usa \t.


Sembra una condizione di gara estremamente rara. Ad ogni modo, crea una funzione che accetti la selezione dell'intervallo visivo e esegua l'iterazione della funzione di ricerca fino a quando non viene trovata alcuna corrispondenza, immagino che sarebbe una risposta più intelligente e utile.
albfan,

Sì, o quello. Se vuoi una soluzione più definitiva puoi usare una funzione. Comunque, è sempre bene sapere come fare in ex command, perché questo sarebbe ciò che è dentro la funzione. E no, non è raro. Devi solo avere stringhe con spazi per avere un casino. Non è affatto raro. Ci sono stato. Grazie per aver commentato.
Dr Beco,

Spiega perché / g non è sufficiente per convertire tutti i gruppi di 4 in ciascuna riga in spazi consecutivi in ​​schede, invece di dover eseguire la ricerca più volte.
Bjartur Thorlacius,

Ciao @BjarturThorlacius, il problema è che se rimuovi il ^simbolo, per iniziare la ricerca dall'inizio della linea, rischi di cambiare gli spazi all'interno delle stringhe. Con la ^garanzia garantisci di cambiare solo spazi e tab dall'inizio della riga, quindi rientro. Oltre a ciò, se sei sicuro di fare tutto in una volta, rimuovi ^e corri solo una volta con::%s/\(^I*\)␣␣␣␣/\1^I/g
Dr Beco,

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

Traduzione: cerca ogni istanza di 4 spazi consecutivi (dopo il carattere =), ma solo se l'intera riga fino a quel punto è spazio bianco (utilizza l'asserzione look-behind a larghezza zero \@<=). Sostituisci ogni istanza trovata con un carattere di tabulazione.


1
L'unica soluzione che ha funzionato per espandere 1 spazio in 1 scheda , ma fai attenzione all'unicode nella risposta, ho appena usato :%s/\(^\s*\)\@<= /\t/g- metti il ​​numero appropriato di spazi (per convertire 4 spazi in 1 scheda, metti in 4 spazi) subito dopo il<=
Orwellophile

5

Cambia tutti gli spazi in tab:% s / \ s / \ t / g


Questo è esattamente ciò di cui avevo bisogno. Grazie. L'unica modifica che ho dovuto apportare è stata quella di sostituire ogni 4 spazi con una scheda invece di fare ogni singolo spazio.
Persona anonima

3

Linux: con unexpand(e expand)

Ecco un'ottima soluzione: https://stackoverflow.com/a/11094620/1115187 , principalmente perché utilizza * nix-utilities:

  1. unexpand - spazi -> schede
  2. espandi - tab -> spazi

Linux: script personalizzato

La mia risposta originale

Snippet di Bash per la sostituzione del rientro di 4 spazi (ce ne sono due {4}nello script) con le schede in tutti i .pyfile nella ./appcartella (ricorsivamente):

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

Non modifica 4 spazi nel mezzo o alla fine.

È stato testato su Ubuntu 16.0x e Linux Mint 18


0

Nel mio caso, avevo più spazi (i campi erano separati da uno o più spazi) che volevo sostituire con una scheda. Lo ha fatto:

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

0

Se hai i coreutils GNU installati, considera %!unexpand --first-onlyo per le schede a 4 spazi, considera %!unexpand -t 4 --first-only( --first-onlyè presente nel caso in cui stavi invocando accidentalmente unexpandcon--all ).

Si noti che ciò sostituirà solo gli spazi che precedono i punti di tabulazione prescritti, non gli spazi che li seguono; non vedrai alcuna differenza visiva in vim se non visualizzi le schede in modo più letterale; per esempio, il mio ~/.vimrccontiene set list listchars=tab:▸┈(sospetto che questo sia il motivo per cui pensavi unexpandche non funzionasse).


0

Per usare Vim per rietichettare un set di file (ad esempio tutti i file * .ts in una gerarchia di directory) da dire 2 spazi a 4 spazi, puoi provare questo dalla riga di comando:

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

Quello che sta facendo è usare findper passare tutti i file corrispondenti axargs (l'opzione -print0 su find funziona con l'opzione -0 a xargs per gestire i file con spazi nel nome).

xargs esegue vim in modalità ex ( -e) su ogni file eseguendo il comando ex dato che è in realtà diversi comandi, per cambiare gli spazi iniziali esistenti in schede, ripristinare il tab stop e cambiare le schede in spazi e infine salvare ed uscire.

L'esecuzione in modalità ex impedisce questo: Vim: Warning: Input is not from a terminalper ogni file.


-1

Script Python semplice:

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

Un grosso problema: questo frammento sostituisce tutti i 4 spazi, non solo il rientro (all'inizio della riga)
maxkoryukov

e il secondo: il filtro file non è implementato
maxkoryukov il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.