it-swarm.com.de

Entfernen Sie Anführungszeichen um Ganzzahlen in einer CSV-Datei

In einer großen (> 1 gb) csv-Datei habe ich sowas

"34432", "name", "0", "very long description"

aber stattdessen hätte ich gerne

34432, "name", 0, "very long description".

Ich habe sed angesehen, aber diese Aufgabe ist nicht in meinem Geltungsbereich.

Irgendwelche Ratschläge, wie man das erreicht?

4
Balázs Németh

Perl benutzen:

Perl -ne 's/"(\d+)"/$1/g; print' file.csv > new_file.txt

Die ganze Arbeit erledigt s/"(\d+)"/$1/g where

  • s/patternA/patternB/ wird verwendet, um patternA durch patternB zu ersetzen
  • dann sucht Perl nach einer oder mehreren Ziffern \d+, die in doppelte Anführungszeichen eingeschlossen sind.
  • die Klammern um (\d+) werden verwendet, um die Ziffern zu erfassen und sie als Ersatzmuster mit der Perl-Spezialvariablen $1 wiederzuverwenden.
6
Sylvain Pineau

Ein GNU sed Regex, der für diesen Fall funktionieren sollte, ist

sed -r 's/"([0-9]+)"/\1/g'    

Für pure sed müssen Sie die Gruppierungsklammern und den Modifikator + umgehen

sed 's/"\([0-9]\+\)"/\1/g'

Sie können die Ersetzung bei einigen Versionen von sed, z.

sed -ri 's/"([0-9]+)"/\1/g' file.csv

Sie können auch die POSIX-Klasse [[:digit:]] anstelle des Zeichenbereichs [0-9] verwenden.

6
steeldriver

Ihre Beschreibung des Problems ist nicht sehr spezifisch. Ich gehe davon aus, dass Sie die doppelten Anführungszeichen nur um das 1. und 3. Feld entfernen möchten. Wenn ja, sollte eine der folgenden Möglichkeiten funktionieren:

  1. sed

    sed -r 's/^"([^"]+)"(\s*,\s*[^,]+)\s*,\s*"([^"]+)"/\1\2, \3/' file.csv
    

    Erläuterung

    Der -r ermöglicht erweiterte reguläre Ausdrücke, sodass wir Klammern verwenden können, um Muster zu erfassen, ohne sie zu maskieren. Wir suchen also nach einem Anführungszeichen am Zeilenanfang (^"), gefolgt von einem oder mehreren Nicht-Anführungszeichen ([^"]+) und dem schließenden Anführungszeichen, gefolgt von 0 oder mehr Leerzeichen, a Komma, dann wieder 0 oder mehr Leerzeichen (\s*,\s*), dann eine Strecke von Nicht-Kommas bis zum nächsten Komma (dies definiert das 2. Feld). Schließlich suchen wir nach 0 oder mehr Leerzeichen, einem Komma, und ersetzen dieses durch das erste erfasste Muster (\1), dann das zweite (\2), ein Komma, ein Leerzeichen und das dritte.

  2. Perl

    Perl -pe 's/^"([^"]+)"(\s*,\s*[^,]+)\s*,\s*"([^"]+)"/$1$2, $3/; ' file.csv
    

    Erläuterung

    Der -p bedeutet, dass jede Zeile nach Anwendung des von -e übergebenen Skripts gedruckt wird. Das Skript selbst ist im Grunde derselbe reguläre Ausdruck wie in sed oben. Nur hier ist das erfasste Muster $1.

  3. awk

    awk -F, -v OFS="," '{gsub("\"","",$1)0gsub("\"","",$3);}1;' file.csv 
    

    Erläuterung

    Der -F setzt das Feldtrennzeichen auf ,. OFS ist das Ausgabefeld-Trennzeichen, das ebenfalls auf , gesetzt ist, damit die Zeilen korrekt gedruckt werden. Das gsub ersetzt alle " durch nichts, da es in den Feldern 1 ($1) und 3 ($3) ausgeführt wird und nur die Anführungszeichen entfernt diese Felder. Der 1; ist nur eine awk Abkürzung für "print the line".

5
terdon

Python-Lösung

Das kleine Skript unten verwendet das Befehlszeilenargument file, durchläuft jede Zeile in dieser Datei und unterteilt jede Zeile in eine Liste von Elementen, wobei , als Trennzeichen verwendet wird. Jeder Eintrag wird dann nicht in Anführungszeichen gesetzt und als numerische Zeichenfolge überprüft. Wenn eine Zeichenfolge numerisch ist, wird sie nicht in Anführungszeichen gesetzt.

#!/usr/bin/env python
import sys

with open(sys.argv[1]) as fp:
    for line in fp:
        new_vals = []
        vals = line.strip().split(',')
        for val in vals:
            val = val.strip().rstrip().replace('"','')
            if not val.isdigit(): 
               val = '"' + val  + '"'
            new_vals.append(val)
        print(",".join(new_vals))

Testlauf:

$ cat input.txt
"34432", "name", "0", "very long description" 
"1234", "othe name" , "42", "another description"
$ ./unquote_integers.py  input.txt                                       
34432,"name",0,"very long description"
1234,"othe name",42,"another description"

Zusätzliche Hinweise:

In den Kommentaren wurde gefragt, warum das Skript doppelte Anführungszeichen um jedes Element entfernt, bevor bewertet wird, ob das Element eine numerische Zeichenfolge ist oder nicht. Der Hauptgrund dafür ist, dass durch das Einschließen von doppelten Anführungszeichen ein Element wie "123" zu False ausgewertet wird, d. H. Nicht numerisch. Tatsächlich müssen wir irgendwie bewerten, was in den doppelten Anführungszeichen enthalten ist. Nun gibt es eine alternative Möglichkeit, dies durch Aufnehmen eines Listenausschnitts für jeden Wert zu erreichen. Dies ist jedoch nicht besser als die Verwendung von .replace() von Anfang an. Es verkürzt den Code, aber zumindest in diesem Fall spielt die Kürze eines Skripts keine Rolle - unser Ziel ist es, den Code zum Laufen zu bringen, nicht zum Code-Golfen.

Hier ist die alternative Lösung mit Listenschnitten:

#!/usr/bin/env python
import sys

with open(sys.argv[1]) as fp:
    for line in fp:
        new_vals = []
        vals = line.strip().split(',')
        for val in vals:
            val = val.strip().rstrip() #remove extra spaces
            val = val.replace('"','') if val[1:-1].isdigit() else val
            new_vals.append(val)
        print(",".join(new_vals))
1