手動輸入資料會使資料庫被包含多個換行符的記錄污染。對於只有一列的 60GB 巨大平面檔案中開頭和結尾用雙引號分隔的良好記錄,它們應該始終只跨越一行,如下所示:
“現在可以獲得許多粒線體、許多原核生物和一些核基因組的完整序列。”
對於不良記錄,它們跨越無限數量的多行,如下所示:
「目前吸菸與高風險呈現強烈負相關。
調整伴隨風險因子後的模式。相對於從不
吸煙者,目前吸煙者患高風險的可能性明顯降低
圖案。 」
這些多行記錄禁止 UNIX 指令進行下游檔案分割split
。split
無法智慧地將這些多行識別為單一記錄,這可能導致將單一記錄拆分為單獨的檔案。下面的 Perl 太慢了,無法在分割之前先合併這個大檔案的壞記錄行,因為等待超過 2 小時後 $count 無法列印。
$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 MB 的檔案需要 6 秒。對於 60 GB,這將是 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