Eu acho que o seguinte comando deve funcionar:
:%s/^\(.*\)\(\n\1\)\+$/\1/
Explicação:
Usamos o comando de substituição em todo o arquivo para mudar pattern
para string
:
:%s/pattern/string/
Aqui pattern
está ^\(.*\)\(\n\1\)\+$
e string
é \1
.
pattern
pode ser dividido assim:
^\(subpattern1\)\(subpattern2\)\+$
^
e $
correspondem, respectivamente, ao início da linha e ao final da linha.
\(
e \)
são usados para incluir, subpattern1
para que possamos nos referir a ele mais tarde pelo número especial \1
.
Eles também são usados para delimitar, subpattern2
para que possamos repeti-lo 1 ou mais vezes com o quantificador \+
.
subpattern1
is .*
.
é um metacaractere que corresponde a qualquer caractere, exceto a nova linha, e *
é um quantificador que corresponde ao último caractere 0, 1 ou mais vezes.
Portanto, .*
corresponde a qualquer texto que não contenha nova linha.
subpattern2
é \n\1
\n
corresponde a uma nova linha e \1
corresponde ao mesmo texto que foi correspondido dentro da primeira \(
, \)
que aqui é subpattern1
.
Então, pattern
pode ser lida assim:
um início de linha ( ^
) seguido por qualquer texto contendo nenhuma linha nova ( .*
) seguido por uma nova linha ( \n
), em seguida, o mesmo texto ( \1
), os dois últimos sendo repetido uma ou mais vezes ( \+
), e finalmente um fim de linha ( $
) .
Onde quer que pattern
seja correspondido (um bloco de linhas idênticas), o comando de substituição o substitui pelo string
qual está aqui \1
(a primeira linha do bloco).
Se você deseja ver quais blocos de linhas serão afetados sem alterar nada no seu arquivo, é possível ativar a hlsearch
opção e adicionar o n
sinalizador de substituição no final do comando:
:%s/^\(.*\)\(\n\1\)\+$/\1/n
Para um controle mais granular, você também pode solicitar uma confirmação antes de alterar cada bloco de linhas adicionando o c
sinalizador de substituição:
:%s/^\(.*\)\(\n\1\)\+$/\1/c
Para obter mais informações sobre o comando de substituição :help :s
, leia ,
para os sinalizadores de substituição :help s_flags
,
para os vários metacaracteres e quantificadores :help pattern-atoms
,
e para expressões regulares no vim, leia isso .
Editar: o curinga corrigiu um problema no comando adicionando um $
no final de pattern
.
Também o BloodGain possui uma versão mais curta e legível do mesmo comando.
$
disso, no entanto. Caso contrário, ele fará coisas inesperadas com uma linha que começa com texto idêntico à linha anterior, mas possui outros caracteres à direita. Observe também que o comando básico que você deu é funcionalmente equivalente à minha resposta:%!uniq
, mas os sinalizadores de destaque e confirmação são bons.\n
corresponde ao final da linha e deve evitar isso, mas não. Eu tentei adicionar um$
pouco depois.*
sem sucesso. Vou tentar corrigi-lo, mas se não puder, talvez eu exclua minha resposta ou adicione um aviso no final. Obrigado por apontar este problema.:%s/^\(.*\)\(\n\1\)\+$/\1/
$
corresponde ao final da string , não ao final da linha. Tecnicamente, isso não é verdade - mas quando você coloca caracteres após outras exceções, ele corresponde a um literal em$
vez de qualquer coisa especial. Portanto, usar\n
é melhor para correspondências com várias linhas. (Veja:help /$
)\n
pode ser usado em qualquer lugar dentro do regex, enquanto$
provavelmente deve ser usado apenas no final. Apenas para fazer a diferença entre os dois, editei a resposta escrevendo que\n
corresponde a uma nova linha (o que instintivamente faz você pensar que ainda há algum texto depois) enquanto$
corresponde a um final de linha (o que faz você pensar que não há nada esquerda).Tente o seguinte:
Como na resposta de saginaw , isso usa o comando substituto de Vim. No entanto, ele aproveita alguns recursos extras para melhorar a legibilidade:
\v
significa "muito mágico", ou todos os caracteres, exceto alfanuméricos ( A-z0-9 ) e sublinhado ( _ ) têm um significado especial.O significado dos componentes são:
fonte
\n
e$
.\n
adiciona algo ao padrão: a nova linha de caractere que informa ao vim que o texto a seguir está em uma nova linha. Considerando$
que não adiciona nada ao padrão, simplesmente proíbe uma correspondência se o próximo caractere fora do padrão não for uma nova linha. Pelo menos, é o que eu entendi lendo sua resposta e:help zero-width
.^
, ele não acrescenta nada ao padrão, ele simplesmente impede uma partida a ser feita se o exterior caractere anterior do padrão não é uma nova linha ...+
significa "repita a expressão anterior (caractere ou grupo) 1 ou mais vezes", mas não corresponde a nada. Os^
meios "não podem começar no meio da cadeia" e os$
meios "não podem terminar no meio da cadeia". Observe que eu não disse "linha", mas "corda" lá. O Vim trata cada linha como uma string por padrão - e é aí que\n
entra. Diz ao Vim para consumir uma nova linha para tentar fazer essa correspondência.Se você deseja remover TODAS as linhas idênticas adjacentes, não apenas
Hold
, você pode fazê-lo extremamente facilmente com um filtro externo de dentrovim
::%!uniq
(em um ambiente Unix).Se você quiser fazer isso diretamente
vim
, é realmente muito complicado. Eu acho que existe uma maneira, mas para o caso geral é muito complicado torná-lo 100% funcional e ainda não resolvi todos os bugs.No entanto, neste caso específico , como você pode ver visualmente que a próxima linha que não é duplicada não começa com o mesmo caractere, você pode usar:
O
+
significa a linha após a linha atual. O . refere-se à linha atual. O/^[^H]/-
significa que a linha antes de (-
) a próxima linha que não começa com H.Então d é excluir.
fonte
uniq
(de dentro do vim ou usando o shell) é como eu resolveria isso. Por um lado, tenho certeza deuniq
que manipulará linhas que estão em branco / todos os espaços como equivalentes (não o testaram), mas isso seria muito mais difícil de capturar com um regex. Isso também significa não "reinventar a roda" enquanto estou tentando fazer o trabalho.Uma resposta baseada no Vim:
= Substitua cada linha seguida por ela mesma pelo menos uma vez , pela mesma linha.
fonte
Mais um, assumindo o Vim 7.4.218 ou posterior:
Isso não é necessariamente melhor que as outras soluções.
fonte
Aqui está uma solução baseada em um antigo (2003) vim (golf) de Preben Gulberg e Piet Delport.
%g/^\v(.*)\n\1$/d
:Uniq
(equivalente a:%Uniq
),:1,Uniq
(desde o início do buffer até a linha atual),:Uniq<cr>
(expandido pelo vim into:'<,'>Uniq
):h range
)Aqui está o código:
Nota: suas primeiras tentativas foram:
fonte