Unix: busque y reemplace comas consecutivas por canalizaciones consecutivas

Jan 08 2021

Estoy convirtiendo un archivo CSV entre comillas dobles en un archivo txt delimitado por canalización en Unix. He utilizado el siguiente comando sed para reemplazar "," en | luego elimine las comillas dobles iniciales y finales.

sed -e 's/","/|/g' -e 's/"//g' filenm.csv > filenm.txt

Pero el archivo parece tener comas consecutivas sin comillas dobles y no se reemplazan.

Col1|col2|col3|col4|col5|col6|col7|col8
Val1|val2|val3,,,,val7|val8

Ahora quiero convertir todas estas comas consecutivas en canalizaciones consecutivas, ya que indican campos vacíos o nulos.

Y otros campos también tienen comas dentro de los valores de campo que no deben modificarse.

Intenté usar a continuación para eso, pero no funcionó.

sed -e 's/,{1,\}/|{1,\}/g' filenm.csv > filenm.txt

archivo csv de muestra abierto en el bloc de notas:

"ID","Name","DOB","Age","Address","City","State","Country","Phone number"
"123","ABC","12/20/2020","15","No.38,3rd st, RRR NNN, TRT",,,,"9999999999"
"456","DEF","12/20/2020",,,,,"test-country","9999999999"
"465","XYZ",,,"No.38,3rd st, RRR NNN, TRT",,,,"9999999999"

Espero que esto ayude a reproducir el problema y resolverlo.

Gracias por adelantado....

Respuestas

2 WiktorStribiżew Jan 08 2021 at 22:37

Puede utilizar perl:

perl -pe 's/"([^"]*)"|,/defined($1) ? $1 : "|"/ge' filenm.csv > filenm.txt

Detalles :

  • "([^"]*)"|,- el patrón de expresiones regulares que coincide ", luego captura en el Grupo 1 cualquier cero o más caracteres distintos de "y luego coincide con a ", o simplemente coincide con a ,en todos los demás contextos
  • defined($1) ? $1 : "|"- RHS, reemplazo, que reemplaza el partido ya sea con el valor del Grupo 1 (si el Grupo 1 se emparejó) o con un |(si ,se emparejó)
  • ge- gsignifica global(reemplaza todas las apariciones) y ehace que Perl trate el RHS como una expresión de Perl.

Ver una prueba en línea :

#!/bin/bash
s='"ID","Name","DOB","Age","Address","City","State","Country","Phone number"
"123","ABC","12/20/2020","0","No.38,3rd st, RRR NNN, TRT",,,,"9999999999"'
perl -pe 's/"([^"]*)"|,/defined($1) ? $1 : "|"/ge' <<< "$s"

Producción:

ID|Name|DOB|Age|Address|City|State|Country|Phone number
123|ABC|12/20/2020|0|No.38,3rd st, RRR NNN, TRT||||9999999999
4 potong Jan 08 2021 at 23:05

Esto podría funcionar para usted (GNU sed):

sed -E ':a;s/^(("[^",]*",+)*"[^",]*),/\1\n/;ta;y/,\n/|,/' file

Reemplaza iterativamente ,'s entre "' s con nuevas líneas, luego traduce ,'s para |' s y nuevas líneas para ,'s.

1 RamanSailopal Jan 09 2021 at 00:35

Usando awk:

awk -F \" '{ for(i=1;i<=NF;i++) { if ($i ~ /^[,]{2,}$/) { $i="," } } OFS="\"";gsub("\",\"","\"|\"",$0)}1' sample.csv

Explicación:

awk -F \" '{  # Set the field delimiter to double quote
             for(i=1;i<=NF;i++) { 
               if ($i ~ /^[,]{2,}$/) { 
                  $i="," # Loop through each field and if is contains 2 or more commas, set that field to one comma } } OFS="\""; gsub("\",\"","\"|\"",$0) # Substitute "," for "|"
           }1' sample.csv
1 Daweo Jan 09 2021 at 01:50

Usaría GNU AWKde la siguiente manera. Deja que el file.txtcontenido sea

"ID","Name","DOB","Age","Address","City","State","Country","Phone number"
"123","ABC","12/20/2020","15","No.38,3rd st, RRR NNN, TRT",,,,"9999999999"
"456","DEF","12/20/2020",,,,,"test-country","9999999999"
"465","XYZ",,,"No.38,3rd st, RRR NNN, TRT",,,,"9999999999"

luego

awk 'BEGIN{FS="\"";OFS=""}{for(i=1;i<=NF;i+=2){$i=gensub(/,/,"|","g",$i)};print $0}' file.txt

producción

ID|Name|DOB|Age|Address|City|State|Country|Phone number
123|ABC|12/20/2020|15|No.38,3rd st, RRR NNN, TRT||||9999999999
456|DEF|12/20/2020|||||test-country|9999999999
465|XYZ|||No.38,3rd st, RRR NNN, TRT||||9999999999

Supuse que la primera y la última columna nunca están vacías. Lo uso "como separador de campo y luego en cada campo impar (estos contienen únicamente ,) cambio todo ,a |. Finalmente imprimo toda esa línea alterada.

(probado en GNU Awk 5.0.1)