Text-Processing
在一個巨大的(70GB)、一行、文本文件中替換字元串
我有一個巨大的(70GB),一行文本文件,我想替換其中的一個字元串(令牌)。我想
<unk>
用另一個虛擬令牌(手套問題)替換令牌。我試過
sed
:sed 's/<unk>/<raw_unk>/g' < corpus.txt > corpus.txt.new
但輸出文件
corpus.txt.new
有零字節!我也嘗試使用 perl:
perl -pe 's/<unk>/<raw_unk>/g' < corpus.txt > corpus.txt.new
但我遇到了記憶體不足的錯誤。
對於較小的文件,上述兩個命令都有效。
如何替換字元串是這樣的文件? 這是一個相關的問題,但沒有一個答案對我有用。
編輯:如何將文件分成 10GB(或其他)的塊並應用
sed
到每個塊上,然後將它們合併cat
?那有意義嗎?有沒有更優雅的解決方案?
通常的文本處理工具並非旨在處理不適合 RAM 的行。他們傾向於通過讀取一條記錄(一行)、操作它並輸出結果,然後繼續處理下一條記錄(行)來工作。
如果有一個 ASCII 字元經常出現在文件中而沒有出現在
<unk>
or<raw_unk>
中,那麼您可以使用它作為記錄分隔符。由於大多數工具不允許自定義記錄分隔符,因此在該字元和換行符之間進行交換。tr
處理字節,而不是行,因此它不關心任何記錄大小。假設;
有效:<corpus.txt tr '\n;' ';\n' | sed 's/<unk>/<raw_unk>/g' | tr '\n;' ';\n' >corpus.txt.new
您還可以錨定在您正在搜尋的文本的第一個字元上,假設它在搜尋文本中沒有重複並且它出現的頻率足夠高。如果文件可能以 開頭
unk>
,請將 sed 命令更改為sed '2,$ s/…
以避免虛假匹配。<corpus.txt tr '\n<' '<\n' | sed 's/^unk>/raw_unk>/g' | tr '\n<' '<\n' >corpus.txt.new
或者,使用最後一個字元。
<corpus.txt tr '\n>' '>\n' | sed 's/<unk$/<raw_unk/g' | tr '\n>' '>\n' >corpus.txt.new
請注意,此技術假定 sed 對不以換行符結尾的文件無縫執行,即它處理最後的部分行而不截斷它並且不附加最終的換行符。它適用於 GNU sed。如果您可以選擇文件的最後一個字元作為記錄分隔符,您將避免任何可移植性問題。
對於這麼大的文件,一種可能是 Flex。讓
unk.l
:%% \<unk\> printf("<raw_unk>"); %%
然後編譯並執行:
$ flex -o unk.c unk.l $ cc -o unk -O2 unk.c -lfl $ unk < corpus.txt > corpus.txt.new