Unix: Suchen Sie nach aufeinanderfolgenden Kommas und ersetzen Sie diese durch aufeinanderfolgende Pipelines

Jan 08 2021

Ich konvertiere eine CSV in doppelten Anführungszeichen in eine durch Pipelines getrennte txt-Datei in Unix. Ich habe den folgenden sed-Befehl verwendet, um "," in | zu ersetzen Entfernen Sie dann das doppelte Anführungszeichen am Anfang und am Ende.

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

Die Datei scheint jedoch aufeinanderfolgende Kommas ohne doppelte Anführungszeichen zu haben und wird nicht ersetzt.

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

Jetzt möchte ich alle diese aufeinanderfolgenden Kommas in aufeinanderfolgende Pipelines konvertieren, da sie leere oder Nullfelder anzeigen.

Andere Felder haben auch Kommas in Feldwerten, die nicht geändert werden sollten.

Ich habe versucht, unten dafür zu verwenden, aber es funktioniert nicht.

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

Beispiel-CSV-Datei im Editor geöffnet:

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

Ich hoffe, dies hilft, das Problem zu reproduzieren und zu lösen.

Danke im Voraus....

Antworten

2 WiktorStribiżew Jan 08 2021 at 22:37

Sie können verwenden perl:

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

Details :

  • "([^"]*)"|,- Das Regex-Muster, das übereinstimmt ", erfasst dann in Gruppe 1 alle null oder mehr Zeichen außer "und stimmt dann mit a überein "oder stimmt ,in allen anderen Kontexten nur mit a überein
  • defined($1) ? $1 : "|"- RHS, Ersatz, der die Übereinstimmung entweder durch den Wert der Gruppe 1 (wenn Gruppe 1 übereinstimmte) oder durch einen Wert |(wenn der ,übereinstimmte) ersetzt.
  • ge- gsteht für global(ersetzt alle Vorkommen) und elässt Perl die RHS als Perl-Ausdruck behandeln.

Sehen Sie sich einen Online-Test an :

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

Ausgabe:

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

Dies könnte für Sie funktionieren (GNU sed):

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

Ersetzen Sie iterativ ,'s zwischen "' durch Zeilenumbrüche und übersetzen Sie dann ,'s für |' s und Zeilenumbrüche für ,'s.

1 RamanSailopal Jan 09 2021 at 00:35

Verwenden von awk:

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

Erläuterung:

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

Ich würde GNU AWKfür diesen folgenden Weg verwenden. Lass den file.txtInhalt sein

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

dann

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

Ausgabe

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

Ich nahm an, dass die erste und letzte Spalte niemals leer ist. Ich benutze "als Feldtrennzeichen und ,ändere dann in jedem ungeraden Feld (das nur enthält ) alles ,in |. Schließlich drucke ich eine ganze solche geänderte Zeile.

(getestet in GNU Awk 5.0.1)