Algum editor de texto que possa aplicar alguma matemática ao texto de substituição?

15

Eu tenho um arquivo XML grande

<obj param="2542">
<obj param="2333">
<obj param="6433">

Eu preciso aumentar todos os valores "param" em algum número. Posso combinar os números necessários com a pesquisa regexp em muitos editores, mas como aplicar matemática à substituição?

serg
fonte
1
Qual sistema operacional? Você ficaria feliz com um script de shell (o que seria bastante fácil)? De qualquer forma, tenho certeza vime emacsposso fazer esse tipo de coisa, mas pode ser necessário escrever um script em vez de usar um único comando.
frabjous
@frabjous sob janelas. Prefiro não escrever nada, se possível. Mas se você postar um script de shell, tenho certeza de que será útil para muitos.
serg

Respostas:

18

Depois de um pouco mais bisbilhotando, o vim pode fazer isso com um único comando, sem scripts. Por exemplo, para adicionar 50 a todos os números a seguir, <obj param="você pode usar:

:%s@<obj param="\(\d\+\)@\='<obj param="' . (submatch(1) + 50)@g

Deixe-me explicar isso.

: é a maneira geral de entrar / significar o modo de linha de comando no vim.

%meios dentro do escopo de todo o documento; você pode colocar em um intervalo numérico, por exemplo,1,50 apenas dentro das 50 primeiras linhas.

s é uma abreviação para substituto (você pode escrever a palavra inteira, se preferir)

@é o delimitador; você pode usar qualquer outro caractere, desde que não esteja no que está procurando. Apenas use três vezes. (A sintaxe é semelhante a sed.)

Tudo até a próxima ocorrência do delimitador @ é o padrão regular a ser procurado, neste caso <obj param="seguido por \d\+, que é qualquer número de dígitos. O \(e \)está lá para definir toda essa sequência de dígitos como um único grupo reg ex que corresponderia a referências anteriores como \1o submatchcomando vim .

Em seguida, o delimitador @marca o que segue como texto de substituição.

O \=começo aqui significa substituir o resultado de alguma expressão avaliada, em vez de um padrão ou sequência regular, que é a chave aqui.

Depois, temos '<obj param="'o início do texto de substituição. A .seguir, é apresentada a função do vim para concatenar seqüências de caracteres.

submatch(1)é uma função interna do vim que pode ser usada apenas dentro de um comando de substituição e retorna a sequência que é igual à regex \1; você usaria submatch(2)para o equivalente a regex \2e assim por diante. ( \0é todo o padrão correspondente, mas não queremos isso aqui.) O \(e \)no padrão de pesquisa são usados ​​para marcar o que conta submatch(1).

Daí (submatch(1) + 50)o resultado da adição de 50 ao número que os dígitos seguintes<obj param=" no formulário de padrão de pesquisa.

O delimitador @é novamente usado para marcar o final do texto de substituição.

A bandeira gé usada para tornar as substituições globais; você pode omitir isso se quiser substituir apenas a primeira instância em cada linha.

Você provavelmente pode descobrir como adicionar números diferentes, subtrair, dividir etc.

frabjous
fonte
Isso é ótimo, eu tinha um arquivo GPX corrompido porque os valores de longitude eram totalmente inválidos. Felizmente, a latitude estava boa, então, usando um mapa, consegui descobrir qual deveria ser o primeiro valor correto, fazer algumas contas e descobrir que era necessário subtrair 4294.567548 de cada valor para acertar. O único obstáculo que eu tinha era que esse método não funcionava em um número de ponto flutuante; portanto, fiz apenas cada lado do ponto decimal como substituições separadas, uma -4294 e uma -567548.
stuffe
7

No Emacs (desde a versão 23): use \,para executar o código Lisp arbitrário na substituição do regexp . Por exemplo, para quadrado os números que você poderia usar

M-x replace-regexp
param="\([0-9]+\)"
param="\,(* \#1 \#1)"

No Vim: inicie o texto de substituição com \=(consulte :help sub-replace-special). Por exemplo, para colocar os números ao quadrado:

s!param="\([0-9]\+\)"!\='param="'.submatch(1)*submatch(1).'"'!

Vários editores permitem que você faça esse tipo de coisa com macros: defina uma macro que 1. procure a próxima correspondência e 2. execute a substituição (usando uma ferramenta externa para aritmética, se necessário); repita a macro quantas vezes você tiver correspondências.

Gilles 'SO- parar de ser mau'
fonte
Resposta subestimada. Curto e você cobre 2 editores + caso geral.
Derekv 30/05
1

Você pode usar o vim para fazer isso por você. Basta abrir seu arquivo e gravar uma macro . Exemplo: pesquise qualquer número

/[0-9]{1,}

depois pressione q e a (armazene a macro no registro a). Depois disso, pressione Ctrl-X (aumentando o número em 1) e pressione n (para o próximo resultado da pesquisa) depois. Depois de fazer isso, pressione q novamente para salvar a macro. Agora você pode aplicar a macro ao próximo número pressionando @ + a. Isso mudará o número atual e passará para o próximo. Repetindo isso ou usando x @ a, você pode repetir esse x vezes.

Bem, essa descrição pode não ser suficiente para mostrar como isso pode ser feito. Basta consultar um tutorial que descreve o mecanismo de macro no vim.

evnu
fonte
E se eu precisar alterar o número não por 1, mas por um milhão? Ou talvez use alguma multiplicação / divisão?
serg
1
É fácil se você deseja adicionar um x constante a cada número: x + Ctrl + a. Você precisa adicionar números diferentes?
evnu 27/09/10