¿Algún editor de texto que pueda aplicar algunas matemáticas al texto de reemplazo?

15

Tengo un gran archivo XML

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

Necesito aumentar todos los valores de "param" en algún número. Puedo hacer coincidir los números que necesito con la búsqueda de expresiones regulares en muchos editores, pero ¿cómo aplicar algunas matemáticas al reemplazo?

serg
fuente
1
Que sistema operativo ¿Estaría contento con un script de shell en su lugar (que sería bastante fácil)? De todos modos, estoy seguro vimy emacspuedo hacer este tipo de cosas, pero podría requerir escribir un script en lugar de usar un solo comando.
frabjous
@frabjous debajo de las ventanas. Prefiero no escribir nada si es posible. Pero si publica un script de shell, estoy seguro de que será útil para muchos.
serg

Respuestas:

18

Después de hurgar un poco más, resulta que vim puede hacerlo con un solo comando, sin secuencias de comandos. Por ejemplo, para agregar 50 a todos los números siguientes <obj param=", puede usar:

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

Déjame desglosar eso.

: es la forma general de ingresar / significar el modo de línea de comandos en vim.

%significa dentro del alcance de todo el documento; podría poner un rango de números, por ejemplo, 1,50para hacerlo dentro de las primeras 50 líneas.

s es una forma abreviada de sustituto (puede escribir la palabra completa si lo prefiere)

@es el delimitador; podrías usar cualquier otro personaje siempre que no esté en lo que estás buscando. Solo úsalo tres veces. (La sintaxis es similar a sed).

Todo hasta la próxima aparición del delimitador @ es el patrón regular a buscar, en este caso <obj param="seguido de \d\+, que es cualquier número de dígitos. El \(y \)está ahí para establecer esta secuencia completa de dígitos como un solo grupo de registro anterior que coincidiría con las referencias anteriores como \1, o el submatchcomando de vim .

Luego, el delimitador @marca lo que sigue como texto de reemplazo.

El \=en los medios que comienzan aquí para sustituir el resultado de una expresión evaluada, en lugar de un patrón reg ex o cadena, que es clave aquí.

Luego tenemos '<obj param="'para el inicio del texto de reemplazo. Lo .que sigue es la función de vim para concatenar cadenas.

submatch(1)es una función incorporada de vim que solo se puede usar dentro de un comando de sustitución y devuelve la cadena que es la misma que la expresión regular \1; lo usarías submatch(2)para el equivalente de expresiones regulares \2y así sucesivamente. ( \0es todo el patrón coincidente, pero no queremos eso aquí). El \(y \)en el patrón de búsqueda se utilizan para marcar lo que cuenta como submatch(1).

Por lo tanto, (submatch(1) + 50)da el resultado de sumar 50 al número que siguen los dígitos <obj param="en el patrón de búsqueda.

El delimitador @se usa nuevamente para marcar el final del texto de reemplazo.

La bandera gse usa para hacer que las sustituciones sean globales; podría omitir esto si solo quisiera reemplazar la primera instancia en cada línea.

A partir de ahí, probablemente pueda averiguar cómo sumar diferentes números, restar, dividir, etc.

precioso
fuente
Esto es genial, tenía un archivo GPX que estaba dañado porque los valores de longitud eran completamente inválidos. Afortunadamente, la latitud estaba bien, así que usando un mapa pude calcular cuál debería ser el primer valor correcto, hacer algunos cálculos y resolver que necesitaba restar 4294.567548 de cada valor para hacerlo bien. El único obstáculo que tuve fue que este método no funcionaba en un número de coma flotante, así que solo hice cada lado del punto decimal como sustituciones separadas, uno -4294 y uno -567548.
estuffe
7

En Emacs (desde la versión 23): use \,para ejecutar código Lisp arbitrario en reemplazo de expresiones regulares . Por ejemplo, para cuadrar los números que podrías usar

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

En Vim: comience su texto de reemplazo con \=(ver :help sub-replace-special). Por ejemplo, para cuadrar los números:

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

Varios editores le permiten hacer este tipo de cosas con macros: defina una macro que 1. busque la siguiente coincidencia y 2. realice el reemplazo (utilizando una herramienta externa para aritmética si es necesario); repita la macro tantas veces como tenga coincidencias.

Gilles 'SO- deja de ser malvado'
fuente
Respuesta infravalorada. Corto y cubres 2 editores + caso general.
derekv
1

Puedes usar vim para hacer eso por ti. Simplemente abra su archivo y grabe una macro . Ejemplo: buscar cualquier número

/[0-9]{1,}

luego presione q y a (almacenar macro en el registro a). Después de eso, presione Ctrl-X (aumentando el número en 1) y luego presione n (para el siguiente resultado de búsqueda). Después de hacerlo, presione q nuevamente para guardar la macro. Ahora puede aplicar la macro al siguiente número presionando @ + a. Esto cambiará el número actual y saltará al siguiente. Al repetir eso o usar x @ a, puede repetir eso x veces.

Bueno, esa descripción puede no ser suficiente para mostrar cómo se puede hacer. Simplemente consulte un tutorial que describe el mecanismo de macro en vim.

evnu
fuente
¿Qué sucede si necesito cambiar el número no por 1 sino por un millón? ¿O tal vez usar algo de multiplicación / división?
serg
1
Es fácil si desea agregar una x constante a cada número: x + Ctrl + a. ¿Necesitas agregar números diferentes?
evnu