Unix: rechercher et remplacer des virgules consécutives par des pipelines consécutifs

Jan 08 2021

Je suis en train de convertir un fichier CSV entre guillemets doubles en fichier txt délimité par pipeline sous Unix. J'ai utilisé la commande sed suivante pour remplacer "," dans | puis supprimez les guillemets doubles de début et de fin.

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

Mais le fichier semble avoir des virgules consécutives sans guillemets doubles et ils ne sont pas remplacés.

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

Maintenant, je veux convertir toutes ces virgules consécutives en pipelines consécutifs car ils indiquent des champs vides ou nuls.

Et d'autres champs ont également des virgules à l'intérieur des valeurs de champ qui ne doivent pas être modifiées.

J'ai essayé d'utiliser ci-dessous pour cela, mais ne fonctionne pas.

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

exemple de fichier csv ouvert dans le bloc-notes:

"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"

J'espère que cela aidera à reproduire le problème et à le résoudre.

Merci d'avance....

Réponses

2 WiktorStribiżew Jan 08 2021 at 22:37

Vous pouvez utiliser perl:

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

Détails :

  • "([^"]*)"|,- le modèle de regex qui correspond ", puis capture dans le groupe 1 n'importe quel zéro ou plus de caractères autres que "puis correspond à a ", ou correspond simplement à a ,dans tous les autres contextes
  • defined($1) ? $1 : "|"- RHS, remplacement, qui remplace la correspondance soit par la valeur du groupe 1 (si le groupe 1 correspondait), soit par un |(si le ,correspondait)
  • ge- gsignifie global(remplace toutes les occurrences) et efait en sorte que Perl traite le RHS comme une expression Perl.

Voir un test en ligne :

#!/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"

Production:

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

Cela pourrait fonctionner pour vous (GNU sed):

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

Remplacez itérativement ,'s entre "' par des nouvelles lignes, puis traduisez ,'s pour |' s et les nouvelles lignes pour ,'s.

1 RamanSailopal Jan 09 2021 at 00:35

En utilisant awk:

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

Explication:

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

J'utiliserais GNU AWKpour la manière suivante. Que le file.txtcontenu soit

"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"

ensuite

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

production

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

J'ai supposé que la première et la dernière colonne ne sont jamais vides. J'utilise "comme séparateur de champ, puis dans tous les champs impairs (ceux-ci contiennent uniquement ,) je change tout ,en |. Enfin, j'imprime toute la ligne modifiée.

(testé dans GNU Awk 5.0.1)