¿Es posible insertar texto condicionalmente a través de la sustitución de expresiones regulares en Vim?
Frecuentes
Visto 320 veces
4
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.
7 Respuestas
4
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
4
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
3
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
2
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
1
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.
0
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
0
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 regex vim or haz tu propia pregunta.
Es probable que no necesite una expresión regular. Simplemente puede buscar y reemplazar "s04" con "[[servidor: s04]]", ¿correcto? - Jason McCreary
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. - user1410444
Deberías considerar usar
awk
, configurando '|' como separador de campo. - ArjunShankar