awk sed grep

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 modificador r 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 :