Unix: busque y reemplace comas consecutivas por canalizaciones consecutivas
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
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 contextosdefined($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
-g
significaglobal
(reemplaza todas las apariciones) ye
hace 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
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.
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
Usaría GNU AWK
de la siguiente manera. Deja que el file.txt
contenido 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)