XOR duas linhas para ver as diferenças

7

Eu preciso calcular um "XOR" como duas linhas para encontrar todos os caracteres que diferem entre as duas linhas. Eu sei que o vim-diffrecurso pode facilmente conseguir isso, mas para comparar duas linhas, eu queria manter tudo no mesmo buffer.

por exemplo

1wYT4SH8f8VjRA25u8AItlrTdAY4Y7n-g8if8VjRA3q25u8AItlrTdwTbv8if8VjRA3q25u8AItlrTdJjMY
1wYT4SH8f8VjRA25u8AItlrTdAY4Y7n-g8if8VjRA3q25u8AIt1rTdwTbv8if8VjRA3q25u8AItlrTdJjMY
                                                  1

Como pode ser feito ?

nobe4
fonte

Respostas:

13

Esta solução não mostra a diferença entre as duas linhas, mas as destaca e permite navegar através delas com ne Ndesta forma:

Elenco da tela da função

Para fazer isso, adicione esta função ao seu .vimrc:

function! CompareLines(line1, line2)
    let l1 = getline(a:line1)
    let l2 = getline(a:line2)
    let pattern = ""

    for i in range(strlen(l1))
        if strpart(l1, i, 1) != strpart(l2, i, 1)
            if pattern != ""
                let pattern = pattern . "\\|"
            endif
            let pattern = pattern . "\\%" . a:line1 . "l" . "\\%" . ( i+1 ) . "c"
            let pattern = pattern . "\\|" . "\\%" . a:line2 . "l" . "\\%" . ( i+1 ) . "c"
        endif
    endfor

    execute "let @/='" . pattern . "'"
    set hlsearch
    normal n
endfunction

Você pode chamar a função com :call CompareLines(1, 2)onde os argumentos são os números das linhas a serem comparadas.

Para adicionar um pouco mais de detalhes sobre como a função funciona:

  • As primeiras linhas obtêm as linhas para comparar em algumas variáveis.
  • O loop percorre essas strings. Cada caractere das seqüências de caracteres é comparado e, quando não corresponde, um padrão do formulário \%Xl\%Ycé adicionado à variável patternwhere Xe Ysão a linha e a coluna de um caractere.

    (Veja :h /ordinary-atome especialmente as últimas linhas que explicam que o padrão \%23lpermite coincidir com a 23ª linha e \%23ca 23ª coluna)

  • Uma vez que o padrão é construído, ele é injetado no registro de pesquisa ( let @/=permita definir o conteúdo do registro e o padrão deve ser citado).

  • Finalmente, set hlsearché usado para destacar todas as correspondências do padrão e normal ntraz o cursor para o primeiro caractere diferente.

Nota 1 A função mudará seu histórico de pesquisa.

Nota 2 A parte que usa o padrão para fazer a pesquisa provavelmente poderia ser bastante aprimorada.

E como um bônus Adicione esta linha ao seu .vimrcpara criar um comando que agilizará a chamada da função:

command! -nargs=* CompLines call CompareLines(<f-args>)

Dessa forma, você pode usar de maneira simples :CompLines 1 2para comparar duas linhas.


EDIT E aqui está uma versão aprimorada da função e do comando. A diferença é que você pode chamá-lo de três maneiras diferentes:

  • :CL irá diferir a linha atual e a seguinte
  • :CL 23 irá diferir a linha atual e a linha 23
  • :CL 23 42 irá diferir as linhas 23 e 42

Aqui está o código:

command! -nargs=* CL call CompareLines(<f-args>)

function! CompareLines(...)

    " Check the number of arguments
    " And get lines numbers
    if len(a:000) == 0
        let l1=line(".")
        let l2=line(".")+1
    elseif len(a:000) == 1
        let l1 =line(".")
        let l2 =a:1
    elseif len(a:000) == 2
        let l1 = a:1
        let l2 = a:2
    else
        echom "bad number of arguments"
        return;
    endif

    " Get the content of the lines
    let line1 = getline(l1)
    let line2 = getline(l2)

    let pattern = ""

    " Compare lines and create pattern of diff
    for i in range(strlen(line1))
        if strpart(line1, i, 1) != strpart(line2, i, 1)
            if pattern != ""
                let pattern = pattern . "\\|"
            endif
            let pattern = pattern . "\\%" . l1 . "l" . "\\%" . ( i+1 ) . "c"
            let pattern = pattern . "\\|" . "\\%" . l2 . "l" . "\\%" . ( i+1 ) . "c"
        endif
    endfor

    " Search and highlight the diff
    execute "let @/='" . pattern . "'"
    set hlsearch
    normal n
endfunction

EDIT 2 Fiz um plugin . Você pode instalá-lo com um gerenciador de plugins comum com (por exemplo):

Plug 'statox/vim-compare-lines'
statox
fonte