awk - Cómo reemplazar un personaje entre paréntesis, mantener todo lo demás como está
sed grep (5)
Los datos se ven así:
There is stuff here (word, word number phrases)
(word number anything, word phrases), even more
...
Hay muchos de ellos en diferentes archivos. También hay diferentes tipos de datos, a su alrededor, que no están en el mismo formato. Los datos dentro de las paratheses no pueden cambiar, y siempre están en la misma línea. No tengo que tratar con:
(stuff number,
maybe more here)
Me gustaría poder reemplazar la coma con dos puntos
La salida deseada sería
There is stuff here (word: word number phrases)
(word number anything: word phrases), even more
...
Con perl
$ perl -pe ''s//([^()]+/)/$&=~s|,|:|gr/ge'' ip.txt
There is stuff here (word: word number phrases)
(word number anything: word phrases), even more
$ echo ''i,j,k (a,b,c) bar (1,2)'' | perl -pe ''s//([^()]+/)/$&=~s|,|:|gr/ge''
i,j,k (a:b:c) bar (1:2)
$ # since only single character is changed, can also use tr
$ echo ''i,j,k (a,b,c) bar (1,2)'' | perl -pe ''s//([^()]+/)/$&=~tr|,|:|r/ge''
i,j,k (a:b:c) bar (1:2)
-
e
modified permite usar el código Perl en la sección de reemplazo -
/([^()]+/)
coinciden sin anidar()
con uno o más caracteres dentro -
$&=~s|,|:|gr
realizar otra sustitución en el texto coincidente, el modificadorr
devolverá el texto modificado
Mientras que la solución sed
de @aleatorir se basa en reemplazar una coma individual dentro de paréntesis, hay una manera de reemplazar múltiples comas dentro de paréntesis con sed
, también.
Aquí está el código:
sed ''/(/ {:a s//(([^,()]*/),//1:/; t a}''
o
sed ''{:a;s//(([^,()]*/),//1:/;ta}''
o
sed -E ''{:a;s/(/([^,()]*),//1:/;ta}''
Vea una demostración en línea .
En todos los casos, la parte principal se encuentra entre las llaves. Aquí están los detalles para el patrón POSIX ERE ( sed
con -E
opción):
-
:a;
-
s/(/([^,()]*),//1:/;
- encuentra y captura en el Grupo 1-
/(
- a(
char -
[^,()]*
- cero o más caracteres distintos de,,(
y)
(por lo tanto, solo se eliminarán aquellas comas que estén entre los caracteres más cercanos(
y)
, no dentro(..,.(...,.)
- eliminar(
de la expresión del paréntesis para que también coincida con los últimos patrones) -
/1:
- y reemplace con el contenido del Grupo 1 + dos puntos después
-
-
ta
- loop a:a
si hubo una coincidencia en la iteración anterior.
Aquí hay una versión de awk que usa los paréntesis como separadores de registros :
awk -v RS=''[()]'' ''NR%2 == 0 {sub(/,/,":")} {printf "%s%s", $0, RT}'' file
La cosa entre paréntesis será cada registro par . La variable RT
contiene el carácter que coincide con el patrón RS
para este registro.
Tenga en cuenta que esto solo reemplaza la primera coma del texto entre paréntesis. Si desea reemplazar todo, use gsub
en lugar de sub
Suponiendo que solo hay una coma para reemplazar entre paréntesis, esta expresión POSIX BRE sed
reemplazará con dos puntos:
sed ''s/(/(.*/),/(.*/))/(/1:/2)/g'' file
Si hay más de una coma, solo la última será reemplazada.
En el escenario de comas múltiples, puede reemplazar solo el primero con:
sed ''s/(/([^,]*/),/([^)]*/))/(/1:/2)/g'' file
Usando awk
$ awk -v FS="" -v OFS="" ''{ c=0; for(i=1; i<=NF; i++){ if( $i=="(" || $i ==")" ) c=1-c; if(c==1 && $i==",") $i=":" } }1'' file
There is stuff here (word: word number phrases)
(word number anything: word phrases), even more
-v FS="" -v OFS=""
Establece FS
en nulo para que cada char se trate como un campo.
establecer la variable c=0
. Iterar sobre cada campo usando for
loop y alternar el valor de c
si (
o )
se encuentra.
si c==1
y ,
aparece, reemplázalo por :