¿Es posible insertar texto condicionalmente a través de la sustitución de expresiones regulares en Vim?

Tengo varias líneas de una tabla que estoy convirtiendo de Excel al formato Wiki y quiero agregar etiquetas de enlace para parte del texto en cada línea, si hay texto en ese campo. Comencé el trabajo de conversión y llegué a este punto:

|10.20.30.9||x|-||
|10.20.30.10||x|s04|Server 4|
|10.20.30.11||x|s05|Server 5|
|10.20.30.12|||||
|10.20.30.13|||||

Lo que quiero es cambiar la cuarta columna de, por ejemplo, s04 a [[server:s04]]. No deseo agregar los corchetes de enlace si la línea está vacía o si contiene -. Si eso - es un gran problema, puedo eliminarlo.

Todos mis intentos en expresiones regulares para obtener algo de la línea terminan en el reemplazo de toda la línea.

preguntado el 22 de mayo de 12 a las 15:05

Es probable que no necesite una expresión regular. Simplemente puede buscar y reemplazar "s04" con "[[servidor: s04]]", ¿correcto? -

Pero deseo agregar el texto en todas las líneas donde hay texto en la misma columna que s04, y las columnas anteriores pueden contener texto, por lo que un bloqueo visual no funciona. -

Deberías considerar usar awk, configurando '|' como separador de campo. -

7 Respuestas

Considera usar awk para hacer esto:

#!/bin/bash

awk -F'|' '
{ 
  OFS = "|";
  if ($5 != "" && $5 != "-")
    $5 = "server:" $5;
  print $0
}'

NOTA: He editado este script desde la primera versión. Este actual, en mi opinión, es mejor.

Entonces puedes procesarlo con:

cat $FILENAME | sh $AWK_SCRIPTNAME

La -F'|' interruptor dice awk de usar | como separador de campo. El if/else y printf Las declaraciones son bastante autoexplicativas. Imprime los campos, con 'servidor:' antepuesto a la columna 5, solo si no es "-" or "".

¿Por qué la columna 5 y no la columna 4?: Porque usas | al principio de cada registro. Entonces awk toma el campo 'primero' ($1) para ser una cadena vacía que cree debería haber ocurrido antes esto primero |.

contestado el 22 de mayo de 12 a las 16:05

Esto parece hacer el trabajo en la muestra que das allí (con Vim):

%s/^|\%([^|]*|\)\{3}\zs[^|]*/\=(empty(submatch(0)) || submatch(0) == '-') ? submatch(0) : '[[server:'.submatch(0).']]'/

contestado el 22 de mayo de 12 a las 16:05

¡Funcionó como por arte de magia!. Decidí quitar el - en el campo, facilitando la sustitución. - user1410444

Probablemente sea mejor usar awk como escribe ArjunShankar, pero esto debería funcionar si elimina "-";) No conseguí que funcionara allí.

:%s/^\([^|]*|\)\([^|]*|\)\([^|]*|\)\([^|]*|\)\([^|]\+|\)/\1\2\3\4[[server:\5]]/

Aunque es una estupidez. Los primeros 4 son idénticos (coincidir cualquier cosa hasta | 4 veces). No conseguí que funcionara con {4}. El quinto coincide con las cadenas s04/s05 (solo requiere que no esté vacío, por lo tanto, se debe eliminar "-").

contestado el 22 de mayo de 12 a las 16:05

más fácil sería usar \{3} para que coincida con los tres primeros. También puedes usar [^-|][^|]* para omitir el caso de solo -. Además, intente usar \zs para evitar consumir la primera sección por completo: :%s/^\%(|[^|]*\)\{3}\)|\zs\([^-|][^|]*\)/[[server:\1]]/ - Rampion

Para evitar usar muchos grupos, intente usar \zs y \ze. Para emparejar solo palabras (resolviendo el -problema) puede usar la siguiente expresión regular: \w\{1,} - magnun leno

@MagnunLeno en qué se diferencia \w\+ vs \w{1,}? - seje

@sehe, son iguales, solo tengo la costumbre de usar {1,}. Pero, hay una gran diferencia entre \+ (o {1,}) y {-1,}. El primero es una versión codiciosa (coincide con la mayor cantidad posible) del segundo, que coincide con la menor cantidad posible. - magnun leno

Esta expresión regular puso el | después del campo 4 dentro de la etiqueta [[]]. - user1410444

Agregando un poco más de legibilidad a las ideas dadas por otros:

:%s/\v^%(\|.{-}){3}\|\zs(\w+)/[[server:\1]]/

Trabajo hecho.

Observe cómo {3} indica el número de columnas a omitir. También tenga en cuenta el uso de \v para muy mágico modo de expresión regular. Esto reduce la complejidad de su expresión regular, especialmente cuando usa más caracteres "especiales" que texto literal.

contestado el 23 de mayo de 12 a las 00:05

¡Bonita! Olvidé por completo que podríamos usar el {3} para reducir las repeticiones. ¡Vota por esto! - magnun leno

Esto no funcionó completamente. En algunas líneas donde el cuarto campo está vacío, pero hay texto en el quinto, el quinto se colocó como enlace. - user1410444

Permítanme recomendar el siguiente comando de sustitución.

:%s/^|\%([^|]*|\)\{3}\zs[^|-]\+\ze|/[[server:&]]/

contestado el 24 de mayo de 12 a las 03:05

¡Muy agradable! ¡Esta es probablemente la mejor y más fácil solución al problema! - user1410444

Noté un problema. Cualquier entrada en la columna 4 que contenga uno o más "-" obtendrá un enlace que rodee la parte hasta el primer "-". Dado que decidí eliminar todas las entradas con solo un "-", la expresión regular podría cambiarse a: %s/^|\%([^|]*|)\{3}\zs[^|]\+/[[ servidor:&]]/ - user1410444

@ user1410444: Probablemente me equivoqué en esta parte de la especificación. Para aclarar el problema: ¿Debería el comando ignorar las líneas donde la cuarta columna is un guión, o donde contiene un guion? - ib.

tratan

 :1,$s/|\(s[0-9]\+\)|/|[[server:\1]]|/

asumiendo que su s04, s05 son siempre s y un número

contestado el 22 de mayo de 12 a las 16:05

marcado de mediawiki, por lo que el reemplazo debe ser |[[server:\1]]| - Rampion

Tenga en cuenta que esto reemplazará el primer s04 en el siguiente "|10.20.30.11|s04|x|s05|Server 5|". - Johan Söderberg

@JohanSoderberg: Sí, lo hará, pero asumí que la entrada es como el ejemplo dado y, por lo tanto, no contiene s03 dentro de las primeras columnas. Pero tienes razón, por supuesto. - morador

Una sustitución más simple se puede lograr con esto:

%s/^|.\{-}|.\{-}|.\{-}|\zs\(\w\{1,}\)\ze|/[[server:\1]]/

   ^^^^^^^^^^^^^^^^^^^^                   -> Match the first 3 groups (empty or not);
                       ^^^                -> Marks the "start of match";
                          ^^^^^^^^^^^     -> Match only if the 4th line contains letters numbers and `_` ([0-9A-Za-z_]);
                                     ^^^  -> Marks the "end of match";

Si _personaje es similar a -, puede aparecer pero no debe sustituirse, use la siguiente expresión regular: %s/^|.\{-}|.\{-}|.\{-}|\zs\([0-9a-zA-Z]\{1,}\)\ze|/[[server:\1]]/

contestado el 22 de mayo de 12 a las 18:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.