Re-numera uma lista quando uma nova entrada é inserida

7

Eu tenho um arquivo de texto de entradas numeradas:

1. foo
2. bar 100%
3. kittens
4. eat cake
5. unicorns
6. rainbows

e assim por diante até um grande número. Então, depois de uma linha vazia, um novo bloco começa em 1.

Eu insiro uma nova entrada, substituindo, digamos, 4. e preciso renumerar todas as entradas subseqüentes no bloco:

1. foo
2. bar 100%
3. kittens
4. sunshine <
5. eat cake
6. unicorns
7. rainbows
    
por Zanna 16.08.2016 / 17:32

5 respostas

5

Soluções VIM

Existem duas soluções: uma é automatizar a tecla Ctrl a através de uma seleção, a segunda é através da execução de uma substituição de padrão com submatch(0)+1 sobre a seleção. Primeiro a automação chave.

Comece criando sua lista:

1. foo
2. bar 100%
3. kittens
4. eat cake
5. unicorns
6. rainbows

Inserir uma entrada

1. foo
2. bar 100%
3. kittens
4. eat cake
4. sunshine
5. unicorns
6. rainbows

Posicione seu cursor em 4. sunshine e no modo de comando pressione shift + v , então shift + g . Esta é a seleção visual até o final do arquivo. Você também pode mover o cursor para o final de um bloco da maneira usual.

Pressione : para entrar no modo de comando, e você verá isto: :'<,'> . Agora digite o seguinte:

norm Ctrl + V Ctrl + A

O que o Ctrl-v e ctrl-A fazem é permitir que você insira a chave "exata", então ele será alterado para ^A , realçado. Isso basicamente significa for all lines selected, execute in normal mode keypress Ctrl-A e Ctrl-A, por padrão, incrementa o número sob o cursor. Você verá os números mudarem

Solução em ação:

Antes

Depois

Outra forma seria selecionar tudo desde o primeiro número repetido como antes ( Shift v , então G ), e entrar no comando modo de execução:

:'<,'>s/\v(^\d+)\./\=(submatch(0)+1).'.'/ 
    
por 29.08.2016 / 00:03
13

Você sempre pode adicionar sua nova entrada com a sintaxe x. newentry e depois renumerar tudo com algo como:

awk -F . -v OFS=. '{if (NF) $1 = ++n; else n = 0; print}'
  • -F . : define o separador de campo como . 1
  • -v OFS=. : mesmo para o separador de campos saída ( -F . é a abreviação de -v FS=. ).
  • {...} : no condição para que o código dentro de {...} seja executado para cada linha
  • if (NF) , se o número de campos for maior que 0. Com FS sendo . , isso significa que se a linha atual contiver pelo menos um . . Poderíamos também fazer com que if (length) verifique linhas não vazias.
  • $1 = ++n : defina o primeiro campo para um n incrementado (inicialmente 0, depois 1, depois 2 ...).
  • else n = 0 : else (quando NF == 0) redefine n para 0.
  • print : imprime a linha (possivelmente modificada).

1 A sintaxe é -F <extended-regular-expression> , mas quando <extended-regular-expression> é um único caractere, isso não é tomado como uma expressão regular (onde . significa qualquer caractere), mas como caractere em vez disso.

    
por 16.08.2016 / 18:09
6

O máximo de overkill (e complexidade! e bugs!) pode ser obtido através do módulo perl Text :: Autoformat .

% < input                                                                    
1. foo
2. bar 100%
3. kittens
4. it is getting dark. there may be a grue
4. no seriously, it's getting dark
4. really, you should find a light or something.
4. are you even paying attention? helloooo
4. eat cake
5. unicorns
6. rainbows
% perl -MText::Autoformat -0777 -ple '$_=autoformat $_, { all => 1 }' < input
 1. foo
 2. bar 100%
 3. kittens
 4. it is getting dark. there may be a grue
 5. no seriously, it's getting dark
 6. really, you should find a light or something.
 7. are you even paying attention? helloooo
 8. eat cake
 9. unicorns
10. rainbows
% 

Os resultados reais dependerão da entrada, da saída desejada, das opções aprovadas, etc.

    
por 16.08.2016 / 17:48
3

Usando ferramentas básicas de shell, pode ser feito assim: pode até ser mais simples:

paste -d . <(seq $(wc -l < new.list)) <(cut -d . -f 2- < new.list) 

Vou explicar de fora para dentro:

paste -d . file1 file2 

cria linhas de saída dos arquivos como colunas. -d . define o separador como . , que ficará atrás dos novos números.

commandA <(commandB)

inicia commandB e apresenta a saída como se fosse um arquivo para ler commandA , que espera um nome de arquivo como argumento. (Veja a substituição do comando).

O segundo argumento de paste , <(cut -d . -f 2- < new.list) , produz a segunda coluna inalterada, cada linha do segundo campo em, o que significa iniciar após o . .

O primeiro argumento de paste cria os novos números de linha consecutivos: primeiro conta as linhas usando "wordcount lines": $(wc -l < new.list) e usa esse número para criar uma sequência de números de 1 a contagem, com seq 7 .

    
por 17.08.2016 / 01:46
2

remover números: cut -d" " -f2- < list.txt > temp.txt

insira linha no temp.txt

faça números: cat -n temp.txt| sed -e 's/^[ ]*\([0-9]*\)[ \t]*\(.*\)/. /' > list.txt

    
por 16.08.2016 / 17:38