Unix: rechercher et remplacer des virgules consécutives par des pipelines consécutifs
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
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 contextesdefined($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
-g
signifieglobal
(remplace toutes les occurrences) ete
fait 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
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.
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
J'utiliserais GNU AWK
pour la manière suivante. Que le file.txt
contenu 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)