Die manuelle Dateneingabe führt dazu, dass die Datenbank mit Datensätzen überfrachtet wird, die mehrere Zeilenumbruchzeichen enthalten. Gute Datensätze, die in einer riesigen 60 GB großen Flatfile mit nur einer Spalte am Anfang und am Ende durch doppelte Anführungszeichen abgegrenzt sind, sollten sich immer nur über eine Zeile erstrecken, wie hier:
„Mittlerweile liegen vollständige Sequenzen zahlreicher mitochondrialer, vieler prokaryotischer und mehrerer Kerngenome vor.“
Bei fehlerhaften Datensätzen erstrecken sie sich über eine unbestimmte Anzahl von Mehrfachzeilen, etwa wie folgt:
„Derzeitiges Rauchen war stark und umgekehrt assoziiert mit einem hohen Risiko
Muster, nach Anpassung an begleitende Risikofaktoren. Im Vergleich zu nie
Raucher hatten bei aktuellen Rauchern eine signifikant geringere Wahrscheinlichkeit für ein Hochrisiko
Muster. "
Diese mehrzeiligen Datensätze verhindern eine nachfolgende Dateiaufteilung durch den UNIX-Befehl split
. split
kann diese mehreren Zeilen nicht intelligent als einen einzigen Datensatz erkennen, und dies kann dazu führen, dass ein einzelner Datensatz in mehrere Dateien aufgeteilt wird. Das folgende Perl ist zu langsam, um diese Zeilen für die fehlerhaften Datensätze dieser riesigen Datei vor dem Aufteilen zusammenzuführen, da $count nach einer Wartezeit von mehr als 2 Stunden nicht gedruckt werden kann.
$file=$ARGV[0];
open(INFO, $file) or die("Could not open $file.");
open(OUT, ">out") or die("Could not open $file.");
$mergedline = "";
$count=0;
foreach $line (<INFO>) {
print $count++;
if ($line =~ /^".*"\n$/) {
print OUT $line;
$mergedline = "";
next;
} elsif ($line =~ /"\n$/) {
print OUT $mergedline;
$mergedline = "";
next;
} else {
chomp $line;
$mergedline .= $line;
}
}
close(INFO);
Gibt es einen praktischen UNIX-Befehl, um dieses Problem zu lösen, sodass die Ausgabedatei „sauber“ ist und nur einzeilige Datensätze enthält, die verarbeitet werden können split
?
sed
scheint eine Option zu sein, aber keiner der folgenden Beiträge beantwortet diese Frage:
https://stackoverflow.com/questions/11290616/sed-conditional-merge-of-multiple-lines
http://www.unix.com/shell-programming-and-scripting/80633-sed-combining-multiple-lines-into-one.html
weil die Muster dieser Beiträge zu regelmäßig und konstant sind.
Antwort1
Verwenden Sie diese Option sed
, um nur die geteilten Linien zu verbinden
sed ':a
/".*"$/b
N;s/\n/ /;ba' input >> output
dauert auf meinem System 6 Sekunden für eine 10 MB große Datei. Für 60 GB wären das 10 Stunden.
bbe
ist etwas schneller
bbe -b '/"/:/"/' -o output -e 'y/\n/ /' input
dauert aber immer noch 4 Sekunden.
Ich fürchte, diese Skriptsprachen sind nicht das richtige Werkzeug, um bei extrem großen Dateien gute Ergebnisse zu erzielen. Wie wäre es, ein kleines Programm in zu schreiben C
?
Antwort2
Beispiel mit gawk
:
awk 'BEGIN {RS = "\"\n"} {++n; print $0"\""> n".txt"}' input
Dies bedeutet, dass die Datei input
in eine beliebige Sequenz von "
gefolgt von einem Zeilenumbruch ( \n
) aufgeteilt werden soll. Dadurch werden Zeilenumbrüche ignoriert, die nicht unmittelbar auf ein Anführungszeichen folgen, sodass mehrzeilige Datensätze erhalten bleiben. In diesem Beispiel wird die Ausgabe in eine Textdatei geschrieben, aber wenn Sie den > n".txt"
Teil entfernen, können Sie die Datensätze stattdessen an eine Pipeline senden.
Antwort3
Ihr Perl
Vorgang ist langsam, weil die for
Schleife zum Einlesen der Datei verwendet wird. Sie sollten die Schleife wirklich verwenden while
, da die for
Schleife die gesamte Datei auf einmal in den Speicher lädt. Deshalb dauert das Drucken von $count so lange.
perl -ne '
print,next if /^".*"$/m or /"$/m;
chomp, $_ .= <>, redo unless eof;
' gene.data