Text-Processing

在一個巨大的(70GB)、一行、文本文件中替換字元串

  • May 16, 2019

我有一個巨大的(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

引用自:https://unix.stackexchange.com/questions/413664