Awk

在命令行從文件中刪除多個字元串,高性能

  • July 12, 2018

是否有一種優雅、高性能的單行方式從輸入中刪除多個完整的字元串?

我處理大型文本文件,例如inputfile中的 100 萬行和**hitfile中的 100k 匹配字元串。我有一個 perl 腳本,它將hitfile載入到雜湊中,然後檢查inputfile的每一行中的所有“單詞” ,但對於我的工作流程,我更喜歡腳本的簡單命令。

我尋求的功能等同於:

perl -pe 's/\b(string1|string2|string3)\b)//g' 

或這種嵌套 sed 的方法:

sed -e "$(sed 's:.*:s/&//ig:' hitfile)" inputfile

或在外殼中循環:

while read w; do sed -i "s/$w//ig" hitfile ; done < inputfile

但這些都太貴了。這種稍微更有效的方法有效(如何從文本文件中刪除所有出現的單詞列表?)但它仍然很慢:

perl -Mopen=locale -Mutf8 -lpe '
 BEGIN{open(A,"hitfile"); chomp(@k = <A>)} 
 for $w (@k){s/(^|[ ,.—_;-])\Q$w\E([ ,.—_;-]|$)/$1$2/ig}' inputfile

但是還有其他技巧可以更簡潔地做到這一點嗎?我忽略了其他一些 unix 命令或方法?我不需要正則表達式,我只需要將純/精確字元串與雜湊進行比較(為了速度)。即“pine”不應該匹配“pineapple”,但應該匹配“(pine)”。

例如,我的一個想法是將文件中的單詞擴展為單獨的行

前:

Hello, world!

後:

¶
Hello
, 
world
!

然後用 grep -vf 處理,然後重新建構/加入行。

還有其他可以快速輕鬆地執行的想法嗎?

hitfile你到底有多大?你能展示一些你正在嘗試做的事情的實際例子嗎?由於您尚未提供有關輸入數據的更多詳細資訊,因此這只是針對您的真實數據進行測試和基準測試的一種想法

Perl 正則表達式能夠變得非常大,並且單個正則表達式將允許您一次修改輸入文件。在這裡,我/usr/share/dict/words以建構一個巨大的正則表達式為例,我的行有 ~99k 行,大小約為 1MB。

use warnings;
use strict;
use open qw/:std :encoding(UTF-8)/;

my ($big_regex) = do {
   open my $wfh, '<', '/usr/share/dict/words' or die $!;
   chomp( my @words = <$wfh> );
   map { qr/\b(?:$_)\b/ } join '|', map {quotemeta}
       sort { length $b <=> length $a or $a cmp $b } @words };

while (<>) {
   s/$big_regex//g;
   print;
}

我不需要正則表達式,我只需要將純/精確字元串與雜湊進行比較(為了速度)。即“pine”不應該匹配“pineapple”,但應該匹配“(pine)”。

如果“pine”不應該匹配“pineapple”,您還需要檢查輸入中出現“pine”之前和之後的字元。雖然使用固定字元串方法當然可以,但聽起來像單詞邊界 ( \b) 的正則表達式概念就是您所追求的。

有沒有一種優雅、高性能的單行方式……對於我的工作流程,我更喜歡腳本的簡單命令。

我不確定我是否同意這種觀點。有什麼問題perl script.pl?您可以將它與 shell 重定向/管道一起使用,就像單線一樣。將程式碼放入腳本將使您的命令行變得整潔,並允許您執行複雜的事情,而不會試圖將其全部塞進單行程式碼中。另外,短並不一定意味著快。

您可能想要使用腳本的另一個原因是如果您有多個輸入文件。使用我上面顯示的程式碼,建構正則表達式相當昂貴,因此多次呼叫腳本會很昂貴——在單個腳本中處理多個文件將消除這種成本。我喜歡 UNIX 原則,但對於大數據,呼叫多個程序(有時多次)並在它們之間傳遞數據並不總是最有效的方法,在一個程序中簡化所有程序會有所幫助。


更新:根據評論,足夠的繩子可以射中自己的腳😉程式碼與上面的單行程式碼相同:

perl -CDS -ple 'BEGIN{local$/;($r)=map{qr/\b(?:$_)\b/}join"|",map{quotemeta}sort{length$b<=>length$a}split/\n/,<>}s/$r//g' /usr/share/dict/words input.txt

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