Ручной ввод данных загрязняет базу данных записями, содержащими несколько символов новой строки. Для хороших записей, разделенных двойными кавычками в начале и в конце в огромном плоском файле размером 60 ГБ с одним столбцом, они всегда должны охватывать только одну строку, как здесь:
«Теперь доступны полные последовательности многочисленных митохондриальных, многих прокариотических и нескольких ядерных геномов».
Для плохих записей они охватывают неопределенное количество строк, например:
«Текущее курение было тесно и обратно связано с высоким риском
Модели, после корректировки на сопутствующие факторы риска. Относительно никогда
курильщики, нынешние курильщики значительно реже имели высокий риск
шаблон. "
Эти многострочные записи запрещают последующее разделение файла командой UNIX split
. split
не может разумно распознать эти несколько строк как одну запись, и это может привести к разделению одной записи на отдельные файлы. Perl ниже слишком медленный, чтобы сначала объединить эти строки для плохих записей для этого огромного файла перед разделением, поскольку $count не может быть напечатан после ожидания более 2 часов.
$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);
Есть ли удобная команда UNIX для решения этой проблемы, чтобы выходной файл был «чистым» и содержал только однострочные записи, которые можно обработать split
?
sed
кажется, это вариант, но ни один из следующих постов не отвечает на этот вопрос:
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
потому что шаблоны этих постов слишком регулярны и постоянны.
решение1
Используется sed
только для соединения разделенных линий.
sed ':a
/".*"$/b
N;s/\n/ /;ba' input >> output
На моей системе файл размером 10 МБ загружается за 6 секунд. Для 60 ГБ это займет 10 часов.
bbe
немного быстрее
bbe -b '/"/:/"/' -o output -e 'y/\n/ /' input
но все равно занимает 4 секунды.
Боюсь, эти скриптовые языки не подходят для работы с очень большими файлами. А как насчет написания небольшой программы на C
?
решение2
пример использования gawk
:
awk 'BEGIN {RS = "\"\n"} {++n; print $0"\""> n".txt"}' input
Это говорит о разделении файла input
на любую последовательность, за которой "
следует символ новой строки ( \n
). Это проигнорирует символы новой строки, которые не следуют сразу за кавычками, сохраняя многострочные записи. В этом примере вывод записывается в текстовый файл, но если вы удалите эту > n".txt"
часть, вы можете вместо этого отправить записи в конвейер.
решение3
Ваш Perl
медленный из-за for
цикла, используемого для чтения файла. Вам действительно следует использовать цикл while
, поскольку for
цикл загружает весь файл в память за один раз. Вот почему печать $count занимает вечность.
perl -ne '
print,next if /^".*"$/m or /"$/m;
chomp, $_ .= <>, redo unless eof;
' gene.data