Ich habe eine CSV-Datei mit ca. 1000 Zeilen und dort, wo ich sie importieren soll, erhalte ich einen Fehler bei Zeile 700. Die Einträge in dieser CSV enthalten jedoch Zeilenumbrüche (und sind in Anführungszeichen gesetzt), und daher kann ich mithilfe von awk
oder ähnlichem nicht wirklich schnell anzeigen, was Zeile 700 ist.
Also fand ichGibt es ein robustes Befehlszeilentool zur Verarbeitung von CSV-Dateien?, und habe sowohl csvfix
als auch installiert csvkit
; es scheint jedoch, dass keine dieser Anwendungen das einfache Angeben einer Zeilennummer (oder eines Zeilenbereichs) und deren Ausgabe unterstützt. Zum Beispiel:
$ csvfix help echo
echo input CSV data to output
usage: csvfix echo [flags] [file ...]
where flags are:
-ibl ignore blank input lines
-sep s specify CSV field separator character
-rsep s as for -sep but retain separator on output
-osep s specifies output separator
-hdr s write the string s out as a header record
-ifn ignore field name record
-smq use smart quotes on output
-sqf fields specify fields that must be quoted
-o file write output to file rather than standard output
-skip t if test t is true, do not process or output record
Ich hätte gedacht echo
, dass dies das ist, was ich brauche, sobald ich angeben könnte, welche Zeile(n) wiedergegeben werden soll(en), aber wenn ich mirhttp://neilb.bitbucket.org/csvfix/manual/csvfix16/csvfix.html?unique.html, es werden nur Spalten beschrieben.
Wie könnte ich diese oder andere Tools verwenden, um beispielsweise Zeile 700 (oder die Zeilen 702–705) aus einer CSV-Datei mit 1000 Zeilen einfach auf die Standardausgabe zu übertragen?
BEARBEITEN: Gefunden (http://neilb.bitbucket.org/csvfix/manual/csvfix16/ExpressionLanguage.html) das csvfix
hat:
csvfix find -if '$line == 407' data.csv
... allerdings handelt es sich hierbei tatsächlich um eine Zeilennummer und nicht um eine Zeilennummer. Wenn die Zeile also bei Zeile 406 beginnt, dann in Zeile 407 umbricht und bei 407 endet, gibt der obige Befehl nichts aus. Wenn Sie jedoch eine Zeile zurückgehen, -if '$line == 406'
wird die Zeile gelöscht. Dies ist ebenfalls nützlich, ist aber dennoch keine Zeilennummer....
Antwort1
Der Befehl csvfix find
unterstützt das Ausgeben einer Zeile nach Bereich oder Nummer. Der folgende Befehl extrahiert die Zeilen 3 und 4 aus einer Datei namens file.csv.
csvfix find -if '$line >= 3 && $line < 5' file.csv
Antwort2
Sie können vorübergehend alle in Anführungszeichen gesetzten Zeilenumbrüche entfernen, um normale Textwerkzeuge verwenden und die Zeilenumbrüche erneut hinzufügen zu können.
Beispielsweise im Fall von doppelten Anführungszeichen:
gawk -v RS='"' 'NR % 2 == 0 { gsub(/\n/, "%NEWLINE%") } { printf("%s%s", $0, RT) }' file.csv > tmp.csv
head -n 700 tmp.csv | sed 's/%NEWLINE%/\n/g' > file_1-700.csv
Antwort3
Sie können aus Perls Text::CSV_XS wie folgt eine Position ermitteln:
perl -MText::CSV_XS -E 'open(my $fh, "<:encoding(utf8)", $ARGV[0]) or die "open: $!"; $csv = Text::CSV_XS->new({binary => 1, auto_diag => 9, diag_verbose => 1 } ); while (my $row = $csv->getline($fh)) { say tell $fh }' FILENAME.csv
Beachten Sie das FILENAME.csv
am Ende der Zeile.
Nach erfolgreichem Parsen jeder Zeile wird dieByteVersatz.
Den Einzeiler auspacken:
use Text::CSV_XS;
use feature 'say';
open(my $fh, '<:encoding(utf8)', $ARGV[0]) or die "open: $!";
$csv = 'Text::CSV_XS'->new({'binary' => 1, 'auto_diag' => 9, 'diag_verbose' => 1});
while (my $row = $csv->getline($fh)) {
say tell $fh
}
Ich habe es mit diesem fehlerhaften CSS ( new.css
) gefüttert:
r1c1,"r1
c2",r1c3
r2c1,"r2c2,r2c3
r3c1,r3c2,r3c3
Ausgabe:
18
# CSV_XS ERROR: 2027 - EIQ - Quoted field not terminated @ rec 1 pos 15 field 2
(Wenn es vor der beschädigten Zeile mehr gute Zeilen gegeben hätte, würden mehr Byte-Offsets gedruckt. Verwenden Sie die letzte.)
Nach Byte 18 wurde also ein Fehler gefunden. Daraus lässt sich ganz einfach eine Zeilennummer ableiten: head -c 18 new.csv | wc -l
, die 2 lautet (die Anzahl der guten Zeilen). Der Fehler liegt also in Zeile 3 – und das ist tatsächlich der Fall, das Anführungszeichen um r2c2 ist nicht geschlossen.