Como adicionar números de linha permanentes a um arquivo?

21

Eu tenho um arquivo de texto como este (usando o gVim no Windows)

foo bar baz quux 
corge grault garply 
waldo fred plugh 
[...150 more lines...]
xyzzy thud

Eu quero adicionar um número para cada linha do arquivo. Não usando :set number, mas para adicionar o número como texto que precede cada linha, conforme a seguir, para que o número faça parte do arquivo.

1. foo bar baz quux 
2. corge grault garply 
3. waldo fred plugh 
[...~150 more lines...]
155. xyzzy thud
roblogic
fonte
awké provavelmente a ferramenta para este trabalho. Mas estou no Windows (suspiro).
roblogic
Respondidas aqui já , não importa :)
roblogic
11
Talvez .. Ou isso é mais geral?
muru
É semelhante, mas eu não saberia o que são números de linha permanentes. Em segundo lugar, a outra pergunta é sobre todas as linhas (e a resposta faz isso) para o gVim no Windows especificamente e esta é uma lista numerada simples para um parágrafo apenas no vim comum.
Kenorb
3
Bem, acho que esse post usa "permanente" para indicar que o buffer deve ser modificado e que os números não são algo puramente visual (o mesmo que você). O motivo para especificar o gvim no Windows é evitar utilitários externos como cator nl, que podem criar linhas numéricas, mas geralmente não estão disponíveis no Windows (como OP indica em seus comentários awk). As duas principais soluções são o Vim puro. Por fim, todas as linhas versus um para são apenas uma questão de seleção de intervalo. Claramente, não é um grande problema.
Muni

Respostas:

36

Na moda pura do Vim:

:%s/^/\=line('.').". "

Explicação:

:%s/^/            " the substitution will be applied to the beginning of every line
\=                " the rest of the replacement part is an expression
line('.').". "    " the expression returns the current line number concatenated with a dot and a space

Veja :help \=e :help line().

Usar uma expressão na peça de substituição é muito poderoso e o FWIW é um bom ponto de entrada para o vimscript.

romainl
fonte
Como posso adicionar este comando muito útil a um mapa de teclas no vimrc?
cosmicraga 20/07
Para chegar ao tópico de ajuda do vim para substituição::help sub-replace-expression
akurtser
9

Uma coisa legal das macros do Vim é que elas podem ser recursivas (podem se invocar):

  1. Limpar registro q: qqq
  2. Adicione o número à primeira linha: ggI1.(não esqueça o espaço!)
  3. Volte para o início da linha e comece a gravar uma macro: 0qq
  4. Copie o número: yW
  5. Mova para baixo uma linha e cole o número: +P
  6. Volte para o início da linha e aumente o número: 0<c-a>
  7. Volte para o início da linha (para que a macro não se quebre ao dobrar os números!): 0
  8. Chame a macro uma vez, para torná-la recursiva. Neste momento, ainda não há nada no registo q, então nada vai acontecer: @q.
  9. Salve a macro: q
  10. Ligue para a macro mais uma vez e veja as faíscas voarem !: @@

A macro continuará se invocando até atingir o final do arquivo.

Você pode usar o truque de macro recursivo para muitos outros problemas semelhantes, por isso é bom estar ciente.

Se você não quiser usar uma macro recursiva por algum motivo, poderá omitir as etapas 1 e 8 e usar uma contagem para executar a macro várias vezes, por exemplo 100@q, executará a macro q100 vezes.

Rico
fonte
11
Coisas poderosas, eu me curvo ao seu domínio. Macros são como magia negra para mim ...
roblogic
11
@ropata, uma macro é apenas uma sequência de comandos (principalmente) no modo normal.
romainl
11
@romainl Acho melhor pensar nisso como uma sequência de pressionamentos de tecla .
Ricos
2
@ Rich, pode ser uma sequência de muitas coisas, incluindo comandos ex.
romainl
2
@romainl Sim, é por isso que acho melhor pensar nisso como pressionamentos de tecla. Ele reproduz exatamente o que você digita no teclado (incluindo, como você diz, comandos ex), como se você tivesse digitado tudo manualmente.
Rich
7

Eu gosto de usar o comando global vim para realizar tarefas como esta. Isso se aplica à adição da iteração ao início de uma linha ou à modificação de um símbolo no texto. Parece mais complicado do que as outras soluções, mas é um padrão bastante flexível para usar quando você o tem à mão e é fácil de modificar sem muita reflexão.

Primeiro, escolha seu intervalo (quais linhas você deseja aplicar). Eu costumo usar marcas (por exemplo, mana primeira linha e mbna segunda, mas você também pode usar números de linha ou seleção visual) e, em seguida, insiro uma modificação do seguinte comando (atualmente ajustado para o seu caso de uso)

:let i=1|'a,'bg/^/s/^/\=i.". "/|let i=i+1

Desconstrução

:let i=1

Isso configura a variável icom um valor inicial. Normalmente, as listas começam com 1, então estou configurando i para 1.

|

A barra inicia um novo comando

'a,'b

Isso define o intervalo do próximo comando. Vou de marca aem marca b, que seria definida na primeira e na última linha da sua lista.

g/^/

Este é o comando global. Ele procura no arquivo (ou intervalo) uma expressão regular especificada e executa o restante da linha de comando em cada uma das linhas correspondentes. Estou correspondendo todas as linhas pesquisando "início de linha". Se você tivesse um texto como

Item some txt
other text

Item second item
whatever
Item third

e só deseja colocar esses rótulos na frente Iteme ignorar as outras linhas, faça g/Item/ou g/^Item/substitua (assumindo o texto literal do item)

s/^/\=i.". "/

Isso executa a expressão regular para substituir o início da linha pelo valor de iconcatenado por a .. Geralmente, você pode fazer isso com qualquer coisa (substitua a etiqueta Itempelo número, por exemplo).

|let i=i+1

Mesmo que a barra inicie um novo comando, ela configura um segundo comando para executar no comando global, em vez de após a conclusão da global. O resultado é que incrementamos iantes que a próxima linha seja processada por g. Aqui está outro lugar de flexibilidade. A modificação de i pode ser qualquer coisa (incremento de 2, chame uma função que gera o próximo elemento da sequência de Fibonacci, qualquer que seja).

John O'M.
fonte
7

Adicionar números a todas as linhas

É possível usar :%!nl -baou :%!cat -ncomandos que adicionam números de linha a todas as linhas.

No Windows, você deve ter o Cygwin / MSYS / SUA instalado.

Adicionar números às linhas selecionadas

Para adicionar números apenas às linhas selecionadas, selecione-os no modo visual ( ve cursores) e, quando terminar, execute o comando: :%!nl(ignorar linhas em branco) ou :%!cat -n(linhas em branco incluídas).

Formatação

Para remover espaços extras, selecione-os no bloco visual ( Ctrl+ v) e remova-os ( x).

Para adicionar alguns caracteres ( ., :, )) após os números, selecione-os no bloco visual ( Ctrl+ v), em seguida, acrescentar o personagem ( A, digitar o caractere, em seguida, acabar com Esc).

kenorb
fonte
2
Isso não fornece a mesma formatação que é fornecida na pergunta. No entanto, gosto da simplicidade da solução.
Karl Yngve Lervåg
@ KarlYngveLervåg Obrigado, incluiu isso na resposta.
Kenorb
5

Uma modificação da resposta de romainl :

:%s/^\(\d\+\. \)\?/\=line('.').". "

Isso não apenas adicionará números de linha, mas também substituirá os números de linha existentes, caso eles já estejam lá. Se você inseriu uma linha no meio do caminho, ela renumerará tudo conforme o esperado.

Isso funciona substituindo qualquer número seguido por a. e um espaço no início da linha com um novo número. Obviamente, isso será interrompido se você tiver uma linha que já comece com esse padrão, portanto, use com o pensamento.

A parte adicionada:

  • ^ - Início da linha
  • \( - Iniciar novo subgrupo
  • \d\+ - Combine um dígito uma vez ou mais
  • \. - Combine um ponto ( .) e um espaço .
  • \) - Subgrupo final
  • \? - Torne o grupo opcional, para que funcione como antes, se ainda não houver um número nesta linha.

Dica de bônus:
para remover os números de linha, você pode usar o mesmo padrão com a parte de repetição vazia:

:%s/^\(\d\+\. \)\?//
Martin Tournoij
fonte
5
I1. <esc>^qqyWjP^<C-a>q

Isso numera as duas primeiras linhas e você pode pressionar @qpara numerar as linhas subseqüentes (ou digitar ex. 18@qSe desejar numerar 20 linhas no total).

Explicação:

I1. <esc>  Number the first line
hqq        Go back to the start of the line and start recording a macro
yWjP       Copy the line number to the next line
^<C-a>     Increment the next line's line number
q          Finish recording

A vantagem disso é que ele não requer nenhum comando externo, o que é útil se você estiver trabalhando com o Vim no Windows, por exemplo.

Maçaneta
fonte
Depois de digitar, 1. <esc>hvocê está na segunda coluna, não na primeira coluna. Eu substituiria hpor 0, depois do qual acho que sua solução deve ser muito boa.
Karl Yngve Lervåg
@ KarlYngveLervåg Opa, isso foi um erro de digitação. Obrigado, consertou.
Doorknob
Sem problemas. No entanto, você ainda não atualizou a explicação. Além disso: Em muitos teclados, ^aguarde um segundo caractere para permitir combinações de digitação como ^a -> â. Ainda concordo que seja a melhor solução, mas acho que isso deve ser mencionado também.
Karl Yngve Lervåg
3

Eu acho que a resposta escolhida é a melhor, mas no espírito da variedade, vou oferecer uma alternativa usando um programa externo:

:%!cat -n

Isso filtrará todo o buffer (conforme indicado por %) através do programa externo cat, onde o -nsinalizador precede cada linha de entrada com um número de linha.

Obviamente, isso requer que você tenha catinstalado, o que é verdade para (provavelmente) todos os sistemas do tipo Unix.

Confira :help :range!mais detalhes sobre como filtrar através de programas externos.

tommcdo
fonte
11
Sei que o solicitante está usando o gVim no Windows, portanto essa solução provavelmente não funcionará lá. No entanto, acho que ainda oferece algumas oportunidades para que outras pessoas aprendam com isso.
21415 Tommcdo em 11/02
Se você instalou msysgite adicionou isso ao seu PATH (o IIRC é uma opção de instalação), esta solução também deve funcionar no Windows.
Martin Tournoij
4
cat -nnão é POSIX, mas nlé, portanto, pode ser uma opção melhor.
muru
2

Uma solução um pouco imprudente pode ser a seguinte (tudo que é escrito entre <e> deve ser inserido depois de pressionar Ctrl+ v):

:%normal :redir @"<Enter>:-=<Enter>:redir END<Enter>I<C-R>".<Tab><Esc>kdd

Desconstrução

:%normal {commands}

executa o comando no modo normal em cada linha especificada pelo intervalo, nesse caso, todas as linhas

:redir @"

redireciona todas as saídas feitas pelos comandos ex para o buffer sem nome.

:.=

é um comando ex que exibe o número da linha atual (infelizmente com uma nova linha anterior)

:redir END

pára de redirecionar para o buffer sem nome

I<C-R>".<Tab><Esc>

insere o conteúdo do buffer sem nome com a. e uma guia para a frente de cada linha e sai do modo de inserção.

kdd

vai uma linha e remove a nova linha que é o resultado do comando:. =.

FloriOn
fonte