¿Cómo agregar números de línea permanentes a un archivo?

22

Tengo un archivo de texto como este (usando gVim en Windows)

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

Quiero agregar un número a cada línea en el archivo. No se usa :set number, sino para agregar el número como texto que precede a cada línea, de la siguiente manera, para que el número sea parte del archivo.

1. foo bar baz quux 
2. corge grault garply 
3. waldo fred plugh 
[...~150 more lines...]
155. xyzzy thud
roblogic
fuente
awkEs probablemente la herramienta para este trabajo. Pero estoy en Windows (suspiro).
roblogic
Respondió aquí ya , no importa :)
roblogic
1
Quizás ... ¿O es esto más general?
muru
Es similar, pero no sabría qué son los números de línea permanentes. En segundo lugar, la otra pregunta es sobre todas las líneas (y la respuesta lo hace) para gVim en Windows específicamente y esta es una lista numerada simple para un párrafo solo en vim simple.
kenorb
3
Bueno, supongo que la publicación usa "permanente" para indicar que el búfer debe modificarse y que los números no son algo puramente visual (igual que usted). La razón para especificar gvim en Windows es evitar utilidades externas como cato nl, que pueden hacer líneas numéricas, pero generalmente no están disponibles en Windows (como OP indica en su comentario awk). Las dos soluciones principales son Vim puro. Por último, todas las líneas frente a un párrafo son solo una cuestión de selección de rango. Claramente no es un gran problema.
muru

Respuestas:

37

En la moda pura de Vim:

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

Explicación:

:%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

Ver :help \=y :help line().

Usar una expresión en la parte de reemplazo es muy poderoso y FWIW es un punto de entrada bastante bueno para vimscript.

romainl
fuente
¿Cómo puedo agregar este comando muy útil a un mapa de teclas en vimrc?
cosmicraga
Para llegar al tema de ayuda vim para la sustitución::help sub-replace-expression
akurtser
9

Una cosa buena de las macros de Vim es que pueden recurrir (pueden invocarse):

  1. Borrar registro q: qqq
  2. Agregue el número a la primera línea: ggI1.(¡no olvide el espacio!)
  3. Vuelva al inicio de la línea y comience a grabar una macro: 0qq
  4. Copia el número: yW
  5. Baje una línea y pegue el número: +P
  6. Vuelva al inicio de la línea e incremente el número: 0<c-a>
  7. Vuelva al inicio de la línea (¡para que la macro no se rompa cuando llegue al doble de cifras!): 0
  8. Llame a la macro una vez, para que sea recursiva. En este punto, todavía no hay nada en el registro Q, por lo que no pasará nada: @q.
  9. Guarda la macro: q
  10. ¡Llama a la macro una vez más, y mira volar las chispas !: @@

La macro continuará invocando hasta que llegue al final del archivo.

Puede utilizar el truco macro recursivo para muchos otros problemas similares, por lo que es bueno tenerlo en cuenta.

Si no desea utilizar una macro recursiva por alguna razón, puede omitir los pasos 1 y 8, y usar un conteo para ejecutar la macro varias veces, por ejemplo 100@q, ejecutará la macro q100 veces.

Rico
fuente
1
Cosas poderosas, me inclino ante tu dominio. Las macros son como magia negra para mí ...
roblogic
1
@ropata, una macro es solo una secuencia de comandos (en su mayoría) en modo normal.
romainl
1
@romainl Creo que es mejor pensarlo como una secuencia de pulsaciones de teclas .
Rico
2
@Rich, puede ser una secuencia de muchas cosas, incluidos los comandos ex.
romainl
2
@romainl Sí, por eso creo que es mejor pensarlo como pulsaciones de teclas. Reproduce exactamente lo que escribe en el teclado (incluidos, como usted dice, comandos ex), como si lo hubiera escrito todo manualmente.
Rico
7

Me gusta usar el comando global vim para realizar tareas como esta. Esto se aplica a agregar iteraciones al comienzo de una línea o modificar un símbolo en el texto. Parece más complicado que las otras soluciones, pero es un patrón bastante flexible para usar cuando lo tiene a mano, y es fácil de modificar sin pensarlo demasiado.

Primero, elija su rango (qué líneas desea aplicar esto). Usualmente uso marcas (por ejemplo, maen la primera línea y mben la segunda, pero también puede usar números de línea o selección visual), luego ingreso una modificación del siguiente comando (actualmente ajustado para su caso de uso)

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

Deconstruccion

:let i=1

Esto configura una variable icon un valor inicial. Por lo general, las listas comienzan con 1, por lo que estoy configurando i en 1.

|

La barra inicia un nuevo comando

'a,'b

Esto establece el rango del siguiente comando. Voy de marca aen marca b, que se establecería en la primera línea y la última línea de su lista.

g/^/

Este es el comando global. Busca en el archivo (o rango) una expresión regular dada y ejecutará el resto de la línea de comando en cada una de las líneas que coincidan. Estoy haciendo coincidir cada línea buscando "comienzo de línea". Si tuvieras texto como

Item some txt
other text

Item second item
whatever
Item third

y solo desea poner estas etiquetas al frente Iteme ignorar las otras líneas, hacer g/Item/o en su g/^Item/lugar (asumiendo el texto literal del elemento)

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

Esto ejecuta la expresión regular para reemplazar el comienzo de la línea con el valor de iconcatenado con a .. Generalmente puede hacer esto a cualquier cosa ( Itempor ejemplo, reemplace la etiqueta con el número).

|let i=i+1

Aunque la barra inicia un nuevo comando, configura un segundo comando para que se ejecute dentro del comando global, en lugar de después de que se complete el comando global. El resultado es que incrementamos iantes de que la siguiente línea sea procesada por g. Aquí hay otro lugar de flexibilidad. La modificación de i puede ser cualquier cosa (incremente en 2, llame a una función que genere el siguiente elemento de la secuencia de Fibonacci, lo que sea).

John O'M.
fuente
7

Agregar números a todas las líneas

Es posible usar :%!nl -bao :%!cat -ncomandos que agregarán números de línea a todas las líneas.

En Windows, debe tener instalado Cygwin / MSYS / SUA.

Agregar números a las líneas seleccionadas

Para agregar números solo para las líneas seleccionadas, selecciónelas en modo visual ( vy cursores), luego, cuando haya terminado, ejecute el comando: :%!nl(ignore las líneas en blanco) o :%!cat -n(líneas en blanco incluidas).

Formateo

Para eliminar espacios adicionales, selecciónelos en el bloque visual ( Ctrl+ v) y elimínelos ( x).

Para agregar algunos caracteres ( ., :, )) después de los números, seleccionarlos en el bloque visual ( Ctrl+ v), tiene que poner el carácter ( A, escriba el carácter, y luego terminar con Esc).

kenorb
fuente
2
Esto no le da el mismo formato que se da en la pregunta. Sin embargo, me gusta la simplicidad de la solución.
Karl Yngve Lervåg
@ KarlYngveLervåg Gracias, incluí eso en la respuesta.
kenorb
5

Una modificación de la respuesta de romainl :

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

Esto no solo agregará números de línea, sino que también reemplazará los números de línea existentes si ya están allí. De, si ha insertado una línea a mitad de camino, volverá a numerar todo como se esperaba.

Esto funciona reemplazando cualquier número seguido de a. y un espacio al comienzo de la línea con un nuevo número. Obviamente, esto se romperá si tienes una línea que ya comienza con este patrón, así que úsala con pensamiento.

La parte agregada:

  • ^ - Inicio de línea
  • \( - Iniciar nuevo subgrupo
  • \d\+ - Une un dígito una vez o más
  • \. - Une un punto ( .) y un espacio .
  • \) - Fin de subgrupo
  • \? - Haga que el grupo sea opcional, para que funcione como antes si todavía no hay un número en esta línea.

Sugerencia de bonificación:
para eliminar los números de línea, puede usar el mismo patrón con la parte de repalce vacía:

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

Esto numera las dos primeras líneas, y puede presionar @qpara numerar las líneas siguientes (o escriba ej. 18@qSi desea numerar un total de 20 líneas).

Explicación:

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

El beneficio de esto es que no requiere ningún comando externo, lo cual es útil si está trabajando con Vim en Windows, por ejemplo.

Perilla de la puerta
fuente
Después de escribir, 1. <esc>hestás en la segunda columna, no en la primera columna. Reemplazaría hcon 0, después de lo cual creo que su solución debería ser muy buena.
Karl Yngve Lervåg
@ KarlYngveLervåg Whoops, eso fue un error tipográfico. Gracias, lo arreglé.
Pomo
No hay problema. Sin embargo, aún no ha actualizado la explicación. Además: en muchos teclados, ^espera un segundo carácter para permitir combinaciones de escritura como ^a -> â. Todavía estoy de acuerdo en que es la mejor solución, pero creo que esto también debería mencionarse.
Karl Yngve Lervåg
3

Creo que la respuesta elegida es la mejor, pero en la variedad, ofreceré una alternativa usando un programa externo:

:%!cat -n

Esto filtrará todo el búfer (como se indica mediante %) a través del programa externo cat, donde el -nindicador antepone cada línea de entrada con un número de línea.

Esto, por supuesto, requiere que haya catinstalado, lo cual es cierto para (probablemente) todos los sistemas tipo Unix.

Consulte :help :range!para obtener más detalles sobre el filtrado a través de programas externos.

tommcdo
fuente
1
Me doy cuenta de que el autor de la pregunta está usando gVim en Windows, por lo que esta solución probablemente no funcionará allí. Sin embargo, creo que todavía ofrece alguna oportunidad para que otros aprendan de ello.
tommcdo
Si ha instalado msysgity agregado eso a su PATH (IIRC es una opción de instalación), esta solución también debería funcionar en Windows.
Martin Tournoij
44
cat -nno es POSIX, pero lo nles, por lo que podría ser una mejor opción.
muru
2

Una solución poco complicada podría ser la siguiente (todo lo escrito entre <y> debe insertarse después de presionar Ctrl+ v):

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

Deconstruccion

:%normal {commands}

ejecuta el comando de modo normal en cada línea especificada por el rango, en este caso, cada línea

:redir @"

redirige cada salida realizada por comandos ex al búfer sin nombre.

:.=

es un comando ex que genera el número de línea actual (desafortunadamente con una nueva línea anterior)

:redir END

deja de redirigir al búfer sin nombre

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

inserta el contenido del búfer sin nombre con a. y una pestaña al frente de cada línea y sale del modo de inserción.

kdd

sube una línea y elimina la nueva línea que es el resultado del comando:. =.

FloriOn
fuente