Qualche editor di testo in grado di applicare della matematica al testo sostitutivo?


15

Ho un grande file XML

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

Ho bisogno di aumentare tutti i valori "param" di qualche numero. Posso abbinare i numeri di cui ho bisogno con la ricerca regexp in molti editor, ma come applicare un po 'di matematica alla sostituzione?


1
Quale sistema operativo? Saresti felice con uno script di shell (che sarebbe abbastanza facile)? Ad ogni modo, ne sono sicuro vime emacsposso fare questo genere di cose, ma potrebbe richiedere la scrittura di uno script piuttosto che l'utilizzo di un singolo comando.
frabjous,

@frabjous sotto windows. Preferirei non scrivere nulla, se possibile. Ma se pubblichi uno script di shell sono sicuro che sarà utile a molti.
serg

Risposte:


18

Dopo aver frugato un po 'di più, risulta che Vim può farlo con un solo comando, senza script. Ad esempio, per aggiungere 50 a tutti i numeri seguenti <obj param="è possibile utilizzare:

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

Lasciami scomporre.

: è il modo generale per accedere / indicare la modalità riga di comando in vim.

%significa nell'ambito di tutto il documento; potresti inserire un intervallo di numeri, ad esempio, 1,50per farlo entro le prime 50 righe.

s è una scorciatoia per il sostituto (puoi scrivere l'intera parola se preferisci)

@è il delimitatore; potresti usare qualsiasi altro personaggio purché non sia in quello che stai cercando. Usalo tre volte. (La sintassi è simile a sed.)

Tutto fino alla successiva occorrenza del delimitatore @ è il modello reg ex da cercare, in questo caso <obj param="seguito da \d\+, che è un numero qualsiasi di cifre. Il \(e \)sono lì per impostare questa intera sequenza di cifre come un singolo gruppo di reg ex che corrisponderebbe a riferimenti indietro come \1, o submatchcomando di vim .

Quindi il delimitatore @contrassegna quello che segue come testo sostitutivo.

La \=corrispondenza dei mezzi iniziano qui di sostituire il risultato di qualche espressione valutata, piuttosto che una reg ex modello o stringa, che è la chiave qui.

Quindi abbiamo '<obj param="'per l'inizio del testo di sostituzione. Il .che segue è la funzione di vim per concatenare le stringhe.

submatch(1)è una funzione integrata di vim che può essere utilizzata solo all'interno di un comando di sostituzione e restituisce la stringa che è la stessa di regex \1; useresti submatch(2)per l'equivalente di regex \2e così via. ( \0è l'intero modello abbinato, ma non lo vogliamo qui.) Il \(e e \)nel modello di ricerca vengono utilizzati per contrassegnare ciò che conta come submatch(1).

Da qui (submatch(1) + 50)deriva il risultato dell'aggiunta di 50 al numero seguito dalle cifre <obj param="nel modulo del modello di ricerca.

Il delimitatore @viene nuovamente utilizzato per contrassegnare la fine del testo sostitutivo.

La bandiera gviene utilizzata per rendere globali le sostituzioni; potresti ometterlo se volessi sostituire la prima istanza su ogni riga.

Probabilmente puoi capire da lì come aggiungere numeri diversi, sottrarre o dividere, ecc.


Questo è fantastico, avevo un file GPX che era corrotto perché i valori di longitudine non erano assolutamente validi. Fortunatamente, la latitudine era OK, quindi usando una mappa sono stato in grado di capire quale dovrebbe essere il primo valore corretto, fare alcuni calcoli e capire che dovevo sottrarre 4294.567548 da ciascun valore per farlo nel modo giusto. L'unico ostacolo che ho avuto è stato che questo metodo non ha funzionato su un numero in virgola mobile, quindi ho semplicemente fatto ogni lato del punto decimale come sostituzioni separate, uno -4294 e uno -567548.
stuffe

7

In Emacs (dalla versione 23): usare \,per eseguire codice Lisp arbitrario in sostituzione di regexp . Ad esempio, per quadrare i numeri che potresti usare

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

In Vim: inizia il testo sostitutivo con \=(vedi :help sub-replace-special). Ad esempio, per quadrare i numeri:

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

Diversi editor ti permettono di fare questo tipo di cose con le macro: definisci una macro che 1. cerca la prossima partita e 2. esegue la sostituzione (usando uno strumento esterno per l'aritmetica se necessario); ripeti la macro tutte le volte che hai delle corrispondenze.


Risposta sottovalutata. Corto e copri 2 redattori + caso generale.
Derekv,

1

Puoi usare VIM per farlo per te. Basta aprire il file e registrare una macro . Esempio: ricerca di qualsiasi numero

/[0-9]{1,}

quindi premere qe a (memorizza macro nel registro a). Dopodiché, premi Ctrl-X (aumentando il numero di 1) e successivamente n (per il risultato di ricerca successivo). Dopo averlo fatto, premere di nuovo q per salvare la macro. Ora puoi applicare la macro al numero successivo premendo @ + a. Questo cambierà il numero corrente e salterà a quello successivo. Ripetendolo o usando x @ a, puoi ripetere x volte.

Bene, quella descrizione potrebbe non essere sufficiente per mostrare come si può fare. Basta fare riferimento a un tutorial che descrive il meccanismo macro in vim.


Cosa succede se devo modificare il numero non di 1 ma di un milione? O forse usi qualche moltiplicazione / divisione?
serg

1
È facile se vuoi aggiungere una costante x ad ogni numero: x + Ctrl + a. Devi aggiungere numeri diversi?
evnu,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.