para - vim borrar linea
Fusionar mĂșltiples lĂneas(dos bloques) en Vim (9)
Me gustaría fusionar dos bloques de líneas en Vim, es decir, tomar líneas n..m
y n..m
a las líneas a..b
. Si prefiere una explicación de pseudocódigo: [a[i] + b[i] for i in min(len(a), len(b))]
Ejemplo:
abc
def
...
123
45
...
debe convertirse
abc123
def45
¿Hay una buena manera de hacer esto sin copiar y pegar manualmente?
Así es como lo haría (con el cursor en la primera línea):
qama:5<CR>y$''a$p:5<CR>dd''ajq3@a
Necesitas saber dos cosas:
- El número de línea en el que comienza la primera línea del segundo grupo (5 en mi caso), y
- el número de líneas en cada grupo (3 en mi ejemplo).
Esto es lo que está pasando:
-
qa
registra todo hasta el siguienteq
en un "búfer" ena
. -
ma
crea una marca en la linea actual -
:5<CR>
va al siguiente grupo. -
y$
tira el resto de la línea. -
''a
vuelve a la marca, establecido anteriormente. -
$p
pastas al final de la línea. -
:5<CR>
regresa a la primera línea del segundo grupo. -
dd
borra. -
''a
vuelve a la marca. -
jq
baja una línea y detiene la grabación. -
3@a
repite la acción para cada línea (3 en mi caso)
Ciertamente, puedes hacer todo esto con una sola copia / pegado (utilizando la selección en modo bloque), pero supongo que no es lo que quieres.
Si quieres hacer esto con solo comandos Ex
:5,8del | let l=split(@") | 1,4s/$//=remove(l,0)/
se transformará
work it
make it
do it
makes us
harder
better
faster
stronger
~
dentro
work it harder
make it better
do it faster
makes us stronger
~
ACTUALIZACIÓN: Una respuesta con esta gran cantidad de upvotes merece una explicación más completa.
En Vim, puede utilizar el carácter de canalización ( |
) para encadenar varios comandos Ex, por lo que lo anterior es equivalente a
:5,8del
:let l=split(@")
:1,4s/$//=remove(l,0)/
Muchos comandos Ex aceptan un rango de líneas como argumento de prefijo: en el caso anterior, el 5,8
antes del del
y el 1,4
antes del s///
especifican en qué líneas operan los comandos.
borra las líneas dadas. Puede tomar un argumento de registro, pero cuando no se da uno, se vuelcan las líneas al registro sin nombre, @"
, al igual que la eliminación en el modo normal, let l=split(@")
luego divide las líneas eliminadas en una lista , utilizando el delimitador predeterminado: espacios en blanco. Para trabajar correctamente en la entrada que tenía espacios en blanco en las líneas eliminadas, como:
more than
hour
our
never
ever
after
work is
over
~
necesitaríamos especificar un delimitador diferente, para evitar que "trabajo es" se divida en dos elementos de la lista: let l=split(@","/n")
.
Finalmente, en la sustitución s/$//=remove(l,0)/
, reemplazamos el final de cada línea ( $
) con el valor de la expresión remove(l,0)
. remove(l,0)
altera la lista l
, borrando y devolviendo su primer elemento. Esto nos permite reemplazar las líneas eliminadas en el orden en que las leemos. En su lugar, podríamos reemplazar las líneas eliminadas en orden inverso usando remove(l,-1)
.
Como se mencionó en otra parte, la selección de bloques es el camino a seguir. Pero también puedes usar cualquier variante de:
:!tail -n -6 % | paste -d ''/0'' % - | head -n 5
Este método se basa en la línea de comandos de UNIX. La utilidad de paste
fue creada para manejar este tipo de fusión de líneas.
PASTE(1) BSD General Commands Manual PASTE(1)
NAME
paste -- merge corresponding or subsequent lines of files
SYNOPSIS
paste [-s] [-d list] file ...
DESCRIPTION
The paste utility concatenates the corresponding lines of the given input files, replacing all but the last file''s newline characters with a single tab character,
and writes the resulting lines to standard output. If end-of-file is reached on an input file while other input files still contain data, the file is treated as if
it were an endless source of empty lines.
Los datos de muestra son los mismos que los de rampion.
:1,4s/$//=getline(line(''.'')+4)/ | 5,8d
No creo que lo haga demasiado complicado. Yo solo pondría virtualedit en
( :set virtualedit=all
)
Seleccione el bloque 123 y todo a continuación.
Ponlo después de la primera columna:
abc 123
def 45
... ...
y eliminar el espacio múltiple entre 1 espacio:
:%s//s/{2,}/ /g
Para unir bloques de línea, tienes que hacer los siguientes pasos:
- Ir a la tercera línea:
jj
- Entrar en el modo de bloqueo visual:
CTRL-v
- Fije el cursor al final de la línea (importante para líneas de diferente longitud):
$
- Ir al final:
CTRL-END
- Cortar el bloque:
x
- Ir al final de la primera línea:
kk$
- Pega el bloque aquí:
p
El movimiento no es el mejor (no soy un experto), pero funciona como usted quería. Espero que haya una versión más corta de la misma.
Estos son los requisitos previos para que esta técnica funcione bien:
- Todas las líneas del bloque de inicio (en el ejemplo de la pregunta
abc
ydef
) tienen la misma longitud XOR - la primera línea del bloque de inicio es la más larga, y no te importan los espacios adicionales que se encuentran en el medio) XOR
- La primera línea del bloque inicial no es la más larga, y hay espacios adicionales hasta el final.
Puede haber muchas formas de lograr esto. Combinaré dos bloques de texto usando cualquiera de los dos métodos siguientes.
suponga que el primer bloque está en la línea 1 y el segundo bloque comienza desde la línea 10 con la posición inicial del cursor en la línea número 1.
(/ n significa presionar la tecla enter.)
1. abc
def
ghi
10. 123
456
789
con una macro usando los comandos: copiar, pegar y unir.
qaqqa: + 9y / npkJjq2 @ a10G3dd
con una macro usando los comandos, mueva una línea al número de la línea n y únase.
qcqqc: 10m. / nkJjq2 @ c
Se puede obtener un comando Ex elegante y conciso para resolver el problema combinando los comandos :global
:move
y :join
. Suponiendo que el primer bloque de líneas comienza en la primera línea del búfer, y que el cursor está ubicado en la línea inmediatamente anterior a la primera línea del segundo bloque, el comando es el siguiente.
:1,g/^/''''+m.|-j!
Para una explicación detallada de la técnica utilizada, vea la answer que di a la pregunta "¿ Vim paste -d '''' comportamiento fuera de la caja? ".
Yo usaría repeticiones complejas :)
Dado este:
aaa
bbb
ccc
AAA
BBB
CCC
Con el cursor en la primera "a" en la primera línea, presione lo siguiente:
qq}jdd''''$pkJj0q
y luego presione @q
(y luego puede usar @@
) tantas veces como sea necesario.
Deberías terminar con:
aaaAAA
bbbBBB
cccCCC
(Más una nueva línea).