Creo que el siguiente comando debería funcionar:
:%s/^\(.*\)\(\n\1\)\+$/\1/
Explicación
Usamos el comando de sustitución en todo el archivo para cambiar pattern
a string
:
:%s/pattern/string/
Aquí pattern
está ^\(.*\)\(\n\1\)\+$
y string
está \1
.
pattern
puede desglosarse así:
^\(subpattern1\)\(subpattern2\)\+$
^
y $
coinciden respectivamente un principio de línea y un final de línea.
\(
y \)
se usan para encerrar subpattern1
para que podamos referirnos más tarde por el número especial \1
.
También se usan para encerrar subpattern2
para que podamos repetirlo 1 o más veces con el cuantificador\+
.
subpattern1
Este es .*
.
un metacarácter que coincide con cualquier carácter, excepto una nueva línea, y *
es un cuantificador que coincide con el último carácter 0, 1 o más veces.
Por lo tanto, .*
coincide con cualquier texto que no contenga una nueva línea.
subpattern2
es \n\1
\n
coincide con una nueva línea y \1
coincide con el mismo texto que coincidió dentro de la primera \(
, \)
que aquí estásubpattern1
.
Por pattern
lo tanto, puede leerse así:
un comienzo de línea ( ^
) seguido de cualquier texto que no contenga una nueva línea ( .*
) seguido de una nueva línea ( \n
), luego el mismo texto ( \1
), repitiéndose los dos últimos una o más veces ( \+
), y finalmente un final de línea ( $
) .
Dondequiera pattern
que coincida (un bloque de líneas idénticas), el comando de sustitución lo reemplaza con el string
que aquí está\1
(la primera línea del bloque).
Si desea ver qué bloques de líneas se verán afectados sin cambiar nada en su archivo, puede habilitar la hlsearch
opción y agregar el n
indicador de sustitución al final del comando:
:%s/^\(.*\)\(\n\1\)\+$/\1/n
Para un control más granular, también puede solicitar una confirmación antes de cambiar cada bloque de líneas agregando el c
indicador de sustitución
:%s/^\(.*\)\(\n\1\)\+$/\1/c
Para obtener más información sobre la lectura comando de sustitución :help :s
,
para la sustitución de las banderas :help s_flags
,
para los diversos metacaracteres y cuantificadores leen :help pattern-atoms
,
y expresiones regulares en vim leen este .
Editar: Comodín solucionó un problema en el comando agregando un $
al final de pattern
.
También BloodGain tiene una versión más corta y más legible del mismo comando.
$
embargo, su comando necesita un en él. De lo contrario, hará cosas inesperadas con una línea que comienza con un texto idéntico a la línea anterior, pero tiene algunos otros caracteres finales. También tenga en cuenta que el comando básico que proporcionó es funcionalmente equivalente a mi respuesta de:%!uniq
, pero los indicadores de resaltado y confirmación son agradables.\n
coincide con un final de línea y debería evitarlo, pero no lo hace. Traté de agregar un$
justo después.*
sin éxito. Voy a intentar solucionarlo, pero si no puedo, tal vez elimine mi respuesta o agregue una advertencia al final. Gracias por señalar este problema.:%s/^\(.*\)\(\n\1\)\+$/\1/
$
coincide con el final de la cadena , no con el final de la línea. Esto técnicamente no es cierto, pero cuando coloca caracteres después de él, salvo algunas excepciones, coincide con un literal en$
lugar de algo especial. Por lo tanto, usar\n
es mejor para coincidencias de varias líneas. (Ver:help /$
)\n
puede usarse en cualquier lugar dentro de la expresión regular, mientras$
que probablemente debería usarse solo al final. Solo para hacer una diferencia entre los dos, he editado la respuesta escribiendo que\n
coincide con una nueva línea (que instintivamente te hace pensar que todavía hay algo de texto después) mientras que$
coincide con un final de línea (que te hace pensar que no hay nada izquierda).Intenta lo siguiente:
Al igual que con la respuesta de saginaw , esta usa el comando Vim: sustituto. Sin embargo, aprovecha algunas características adicionales para mejorar la legibilidad:
\v
significa "muy mágico", o todos los caracteres, excepto los alfanuméricos ( A-z0-9 ) y el guión bajo ( _ ) tienen un significado especial.El significado de los componentes son:
fuente
\n
y$
.\n
agrega algo al patrón: la nueva línea de caracteres que le dice a vim que el siguiente texto está en una nueva línea. Mientras$
que no agrega nada al patrón, simplemente prohíbe que se haga una coincidencia si el siguiente carácter fuera del patrón no es una nueva línea. Al menos, es lo que he entendido al leer su respuesta y:help zero-width
.^
, no agrega nada al patrón, solo evita que se haga una coincidencia si el carácter anterior fuera del patrón no es una nueva línea ...+
significa "repetir la expresión anterior (carácter o grupo) 1 o más veces", pero no coincide con nada en sí mismo. El^
medio "no puede comenzar en el medio de la cadena" y$
significa "no puede terminar en el medio de la cadena". Observe que no dije "línea", sino "cadena" allí. Vim trata cada línea como una cadena de forma predeterminada, y ahí es donde\n
entra. Le dice a Vim que consuma una nueva línea para intentar hacer que esta coincidencia.Si desea eliminar TODAS las líneas idénticas adyacentes, no solo
Hold
, puede hacerlo extremadamente fácilmente con un filtro externo desde dentrovim
::%!uniq
(en un entorno Unix).Si quieres hacerlo directamente en
vim
, en realidad es muy complicado. Creo que hay una manera, pero para el caso general es muy complicado hacerlo 100% funcional y aún no he resuelto todos los errores.Sin embargo, para este caso específico , dado que puede ver visualmente que la siguiente línea que no está duplicada no comienza con el mismo carácter, puede usar:
El
+
significa la línea después de la línea actual. Los . se refiere a la línea actual. El/^[^H]/-
significa la línea anterior (-
) la siguiente línea que no se inicia con H.Entonces d es eliminar.
fuente
uniq
(ya sea desde vim o usando el shell) es cómo resolvería esto. Por un lado, estoy bastante seguro deuniq
que manejará líneas en blanco / todos los espacios como equivalentes (no lo probé), pero eso sería mucho más difícil de capturar con una expresión regular. También significa no "reinventar la rueda" mientras trato de hacer el trabajo.Una respuesta basada en Vim:
= Reemplace cada línea seguida por sí misma al menos una vez , con esa misma línea.
fuente
Uno más, suponiendo Vim 7.4.218 o posterior:
Sin embargo, esto no es necesariamente mejor que las otras soluciones.
fuente
Aquí hay una solución basada en un viejo (2003) vim (golf) de Preben Gulberg y Piet Delport.
%g/^\v(.*)\n\1$/d
:Uniq
(equivalente a:%Uniq
),:1,Uniq
(desde el inicio del búfer hasta la línea actual),:Uniq<cr>
(expandido por vim en:'<,'>Uniq
):h range
)Aquí está el código:
Nota: sus primeros intentos fueron:
fuente