2016-04-17 13 views
1

Wenn ich Zeilen wie folgt aus:Entfernen nur einige * * fullstops aus einer CSV-Datei

1,987372,987372,C,T,.,.,.,.,.,.,.,.,1,D,.,.,.,.,.,.,.,1.293,12.23,0.989,0.973,D,.,.,.,.,0.253,0,4.08,0.917,1.048,1.000,1.000,12.998 
1,987393,987393,C,T,.,.,.,.,.,.,.,.,1,D,.,.,.,.,.,.,0.152,1.980,16.09,0.999,0.982,D,-0.493,T,0.335,T,0.696,0,5.06,0.871,0.935,0.998,0.997,16.252 

, wie ich alle Instanzen ,., ersetzen können mit ,?,

I tatsächlichen Dezimalstellen erhalten wollen in die Zahlen, so kann ich nicht nur

tun aber
sed 's/./?/g' file 

wenn dabei:

sed 's/,.,/,?,/g' file 

dies scheint nur in einigen Fällen zu funktionieren. es gibt immer noch Fälle von ,., herumhängen.

Wer hat irgendwelche Zeiger?

Dank

Antwort

3

Dies sollte funktionieren:

sed ':a;s/,\.,/,?,/g;ta' file 

mit aufeinanderfolgenden ,., Strings nach einer Substitution der folgenden . wird erfolgreich war, werden nächste Zeichen verarbeitet, die nicht dem Muster übereinstimmt, so mit Du brauchst einen zweiten Pass.

:a ist ein Label für die kommende Schleife

,\., wird Punkt zwischen Komma entsprechen. Beachten Sie, dass der Punkt maskiert werden muss, da . für die Übereinstimmung eines beliebigen Zeichens (,a, würde mit ,., übereinstimmen).

g ist für allgemeine Substitution

ta Tests vorherige Substitution und, wenn sie erfolgreich ist, Schleifen zu :a Etikett Restsubstitutionen.

+0

danke Kenavoz. Das hat funktioniert. Ich vermutete, dass dies der Fall war. Wenn es dir nichts ausmacht, kannst du erklären, wie jeder Teil funktioniert? Ich verstehe nur wirklich 's \\\\\\\\\ '. und warum vor dem '. – brucezepplin

+0

alles was ich sagen kann ist - sehr schlau! Nochmals vielen Dank – brucezepplin

+1

IMO ist es irgendwie klobig, zwei Pässe zu nehmen, wenn alles, was benötigt wird, ist ein richtiges Regex-Muster für es in einem Rutsch zu arbeiten – Borodin

2

Unter Verwendung von sed ist es möglich, durch eine Schleife ausgeführt wird, wie in oben Antwort jedoch gezeigt Problem leicht perl Kommandozeile mit lookarounds gelöst mit:

perl -pe 's/(?<=,)\.(?=,)/?/g' file 

1,987372,987372,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,?,1.293,12.23,0.989,0.973,D,?,?,?,?,0.253,0,4.08,0.917,1.048,1.000,1.000,12.998 
1,987393,987393,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,0.152,1.980,16.09,0.999,0.982,D,-0.493,T,0.335,T,0.696,0,5.06,0.871,0.935,0.998,0.997,16.252 

Dieser Befehl ist nicht eine Schleife benötigt, weil statt passender Umgebung Komma wir behaupten nur ihre Position mit einem Lookbehind und Lookahead.

0

Sie haben ein Beispiel mit regulären Ausdrücken sed. Ich werde eine Alternative anbieten - analysieren, um die CSV, und dann jedes Ding als ‚Feld‘ behandeln:

#!/usr/bin/perl 

use strict; 
use warnings; 

#iterate input row by row 
while (<DATA>) { 
    #remove linefeeds 
    chomp; 
    #split this row on , 
    my @row = split /,/; 
    #iterate each field 
    foreach my $field (@row) { 
     #replace this field with "?" if it's "." 
     $field = "?" if $field eq "."; 
    } 
    #stick this row together again. 
    print join ",", @row,"\n"; 
} 

__DATA__ 
1,987372,987372,C,T,.,.,.,.,.,.,.,.,1,D,.,.,.,.,.,.,.,1.293,12.23,0.989,0.973,D,.,.,.,.,0.253,0,4.08,0.917,1.048,1.000,1.000,12.998 
1,987393,987393,C,T,.,.,.,.,.,.,.,.,1,D,.,.,.,.,.,.,0.152,1.980,16.09,0.999,0.982,D,-0.493,T,0.335,T,0.696,0,5.06,0.871,0.935,0.998,0.997,16.252 

Dieses ausführlicher ist als es sein muss, um das Konzept zu veranschaulichen. Dies könnte bis zu reduzieren:

perl -F, -lane 'print join ",", map { $_ eq "." ? "?" : $_ } @F' 

Wenn Ihre CSV auch zitieren, dann können Sie das Modul Text::CSV ausbrechen, die das ordentlich verarbeitet.

1

Alles, was notwendig ist, ist eine einzige Substitution

$ perl -pe 's/,\.(?=,)/,?/g' dots.csv 
1,987372,987372,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,?,1.293,12.23,0.989,0.973,D,?,?,?,?,0.253,0,4.08,0.917,1.048,1.000,1.000,12.998 
1,987393,987393,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,0.152,1.980,16.09,0.999,0.982,D,-0.493,T,0.335,T,0.696,0,5.06,0.871,0.935,0.998,0.997,16.252 
0

Sie benötigen 2 Pässe erst seit dem Hinter , auf einer ,., Übereinstimmung gefunden wird nicht verfügbar, um die führenden , auf den nächsten ,., zum Spiel:

$ sed 's/,\.,/,?,/g; s/,\.,/,?,/g' file 
1,987372,987372,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,?,1.293,12.23,0.989,0.973,D,?,?,?,?,0.253,0,4.08,0.917,1.048,1.000,1.000,12.998 
1,987393,987393,C,T,?,?,?,?,?,?,?,?,1,D,?,?,?,?,?,?,0.152,1.980,16.09,0.999,0.982,D,-0.493,T,0.335,T,0.696,0,5.06,0.871,0.935,0.998,0.997,16.252 

Das obige funktioniert in jedem sed auf jedem Betriebssystem.