2016-04-11 2 views
1

Für ein Dataset in einer CSV-Datei, in der die erste Spalte oft leer ist, möchte ich programmatisch ein zusätzliches Komma in jede Zeile einfügen, die nicht mit einem Doppel beginnt Anführungszeichen. Aus dem folgenden Beispiel sehen Sie, dass nur bestimmte Zeilen mit " beginnen und dies sind die Zeilen, die ich ignorieren möchte. Jede andere Zeile sollte eine zusätzliche , bekommen.Ein Zeichen voraussetzen, um Zeilen basierend auf ihrem ersten Zeichen einzugeben

"1967 Universe",1967,"1,141.0",650.6,73.0,417.5,222.6,119.6,309.8,176.0,390.8,225.0,217.8,130.0 
,1968,"1,353.4",694.7,84.3,574.4,234.8,119.2,350.1,182.1,477.3,233.9,291.1,159.5 
,1969,"1,322.3",624.8,85.2,612.4,215.8,104.7,317.0,149.9,470.5,215.6,319.0,154.6 
,1970,"1,351.5",646.8,88.1,616.7,218.3,93.1,287.4,148.1,502.9,246.5,342.9,159.1 
,1971,"1,924.6",906.1,132.9,885.7,303.6,127.3,421.1,208.1,725.4,338.6,474.6,232.1 
"1972 Universe",1972,"2,218.9","1,033.1",148.6,"1,037.2",333.3,147.3,440.8,230.1,905.4,391.5,539.3,264.3 
,1973,"1,819.5",882.1,117.0,820.5,271.9,141.6,361.4,197.5,763.2,323.9,423.1,219.0 
,1974,"1,074.4",643.8,64.4,366.2,165.4,97.2,241.3,154.5,390.1,223.7,277.6,168.4 
,1975,939.2,675.5,63.8,199.8,129.5,92.6,241.5,169.3,292.7,222.8,275.5,190.8 
,1976,"1,296.2",893.6,93.1,309.5,152.4,111.2,326.1,219.4,401.7,292.6,416.0,270.5 
,1977,"1,690.0","1,126.1",121.3,442.7,181.9,126.8,402.4,269.3,561.1,370.1,544.6,359.9 
"1978 Universe",1978,"1,800.5","1,182.6",130.6,487.3,194.4,132.9,388.0,260.8,667.6,439.3,550.5,349.6 
,1979,"1,551.8",981.5,125.4,444.8,166.9,110.2,289.1,182.4,628.0,392.1,467.7,296.7 
,1980,"1,190.6",710.4,114.5,365.7,117.9,75.7,192.0,107.9,561.9,333.0,318.9,193.7 
,1981,985.5,564.3,101.8,319.4,109.8,65.7,133.3,78.3,491.1,270.7,251.3,149.5 
,1982,"1,000.5",546.4,88.3,365.8,106.7,65.7,126.3,67.6,543.5,281.1,224.1,132.0 
,1983,"1,605.2",901.5,133.7,570.1,164.1,112.3,187.8,117.4,862.9,443.0,390.4,228.6 

Ich denke, das mit sed getan werden könnte, aber ich bin nicht vertraut genug mit Regex zu wissen, wie ein bedingten ersetzen zu tun.

Das einzige Beispiel, das ich gefunden habe, die

ähnlich ist

sed -ri 's/[^,]+/REPLACEMENT/' file.csv 
so wäre es wahrscheinlich wie

aussehen
sed -ri 's/[^,]+/,/' file.csv 

aber ich glaube nicht, das ist richtig

sed 's/\,/\,,/' 

funktioniert fast, aber es ersetzt das Komma nach jeder ersten Instanz des Kommas, was nicht das ist, wonach ich suche. Beispiel:

"2004 Universe",,2004,"2,070.1","1,613.4",90.4,366.2,197.0,131.8,370.5,295.5,960.8,756.1,541.9,430.0 
,,2005,"2,155.3","1,682.0",84.0,389.3,203.8,126.6,353.9,278.7,"1,039.0",826.8,558.6,450.0 

Kann jemand helfen?

+0

Wo das Komma hinzugefügt werden sollte? Am Anfang der Linie oder am Ende oder woanders? Idealerweise sollten Sie beide beschreiben, wohin das Komma geht und die gewünschte Ausgabe für die Beispieleingabe anzeigen. –

+0

@ JonathanLeffler: Das Beispiel am Ende impliziert, dass das Komma der Zeile _prepend_ sein sollte; Ich habe den Titel entsprechend geändert. – mklement0

+1

@ mklement0 - stimmten zu, dass alles "vorangestellt" impliziert, aber die Frage sollte es nicht wirklich implizieren; es sollte es sagen. Das Problem mit dem letzten Beispiel ist, dass hinter dem String-Feld ein doppeltes Komma steht, also ist es eigentlich ein Beispiel dafür, dass das letzte 'sed' nicht wie gewünscht funktioniert - und nicht, was eigentlich gewünscht ist.Ich stimme der Schlussfolgerung zu, dass die Schlussfolgerung nicht schwer ist, aber die besten Fragen führen nicht dazu, dass diejenigen, die versuchen zu antworten, irgendetwas ableiten (zumindest über die gewünschte Ausgabe). –

Antwort

2

erweiterte regex Option -r nicht

benötigt
sed -i 's/^,/,&/' file 

wird ein zusätzliches Komma auf den Linien mit Komma beginnen einzufügen.
circumflex gibt den Start der Linie an.

1

Für eine positive Formulierung des Problems - prepend , auf alle Zeilen, die mit , starten - siehe karakfa's answer.

Um , auf allen Linien voranstellen, die mit " nicht starten haben, versuchen Sie Folgendes:

sed -i -r 's/^[^"]/,&/' file.csv 
  • ^[^"] erfasst jede einzelne Zeichen, das kein " ([^"]) am Anfang der Zeile (^) und ersetzt sie durch eine ,, gefolgt von der Zeichenkette, die der Regex (&) entspricht, dh dieser Zeile erstes Zeichen (was in Ihrer Beispieleingabe auch eine , ist).

    • Hinweis der potentiell verwirrenden unterschiedlichen Verwendungen von ^: als Start-of-line-Anker direkt nach dem Öffnen delimiter / auf der einen Seite und als Negationsoperator als das erste Zeichen in dem Klammerausdruck (Zeichen Set) ([^...]) auf der anderen Seite.

    • Beachten Sie, dass Nicht-Standard-Option -r aktiviert Unterstützung für EREs (erweitert reguläre Ausdrücke), während sed standardmäßig erwartet BREs (Grund reguläre Ausdrücke).
      Die oben genannten funktioniert auch ohne -r, aber wenn EREs ist eine Option, sie sind vorzuziehen, weil sie mehr Funktionen bieten und ihre Syntax ist viel mehr als die regulären Ausdrücke in anderen Sprachen.

  • Alle Linien, die, das heißt nicht übereinstimmen, werden alle Zeilen, die mit " Start tun , durchlaufen werden, wie sie ist.

Was was Sie versucht:

sed -ri 's/[^,]+/,/' file.csv 

Streichhölzer ein oder mehr (+) andere Zeichen als ,überall auf der Linie, weil der Ausdruck in eckigen Klammern (Zeichen set) [^,] ist nicht verankert an den Anfang der Zeichenfolge (mit a ^ direkt nach der /).

Abgesehen davon, dass Ihre Ersatzzeichenfolge übernimmt nicht das angepasst String, so wäre es mit , dem Spiel zu ersetzen, anstatt darauf zu vorangestellt wird.

sed 's/\,/\,,/' 

fehlt wieder die des Regex am Anfang des Strings verankert und wird daher die ersten ,überall auf der Linie ersetzen.
(In diesem Fall wird weder \ benötigt).

+1

Vielen Dank für Ihre Antwort mklement0, Sie haben mir geholfen zu verstehen, warum ich auf das Problem stieß und wie man es löst! Ich stimme zu, dass die positive Formulierung des Problems im Vergleich zu dem, was ich letztendlich versuchte, der beste Ansatz sein könnte. Ich werde auch mehr lesen auf Regex, damit ich besser verstehen und verankern! Ich versuchte, beide Antworten als eine Lösung zu akzeptieren, aber es würde mich nur eins wählen lassen: – Lazarix

0

file.csv:

"1967 Universe",1967,"1,141.0",650.6,73.0,417.5,222.6,119.6,309.8,176.0,390.8,225.0,217.8,130.0 
,1968,"1,353.4",694.7,84.3,574.4,234.8,119.2,350.1,182.1,477.3,233.9,291.1,159.5 
,1969,"1,322.3",624.8,85.2,612.4,215.8,104.7,317.0,149.9,470.5,215.6,319.0,154.6 
,1970,"1,351.5",646.8,88.1,616.7,218.3,93.1,287.4,148.1,502.9,246.5,342.9,159.1 
,1971,"1,924.6",906.1,132.9,885.7,303.6,127.3,421.1,208.1,725.4,338.6,474.6,232.1 
"1972 Universe",1972,"2,218.9","1,033.1",148.6,"1,037.2",333.3,147.3,440.8,230.1,905.4,391.5,539.3,264.3 
,1973,"1,819.5",882.1,117.0,820.5,271.9,141.6,361.4,197.5,763.2,323.9,423.1,219.0 

Verwendung:

$ sed 's/^,/,,/' file.csv 

Ausgang:

"1967 Universe",1967,"1,141.0",650.6,73.0,417.5,222.6,119.6,309.8,176.0,390.8,225.0,217.8,130.0 
,,1968,"1,353.4",694.7,84.3,574.4,234.8,119.2,350.1,182.1,477.3,233.9,291.1,159.5 
,,1969,"1,322.3",624.8,85.2,612.4,215.8,104.7,317.0,149.9,470.5,215.6,319.0,154.6 
,,1970,"1,351.5",646.8,88.1,616.7,218.3,93.1,287.4,148.1,502.9,246.5,342.9,159.1 
,,1971,"1,924.6",906.1,132.9,885.7,303.6,127.3,421.1,208.1,725.4,338.6,474.6,232.1 
"1972 Universe",1972,"2,218.9","1,033.1",148.6,"1,037.2",333.3,147.3,440.8,230.1,905.4,391.5,539.3,264.3 
,,1973,"1,819.5",882.1,117.0,820.5,271.9,141.6,361.4,197.5,763.2,323.9,423.1,219.0 
Verwandte Themen