sed/perl正则表达式非常慢



所以,我有一个名为cracked.txt,其中包含数千(8000多万)行以下内容:

dafaa15bec90fba537638998a5fa5085:_BD:zzzzzz12
a8c2e774d406b319e33aca8b38540063:2JB:zzzzzz999
d6d24dfcef852729d10391f186da5b08:WNb:zzzzzzzss
2f1c72ccc940828b5daf4ab98e0f8731:@]9:zzzzzzzz
3b7633b6c19d79e5ab76bdb9cce4fd42:#A9:zzzzzzzz
a3dc9c03ff845776b485fa8337c9625a:yQ,:zzzzzzzz
ade1d43b29674814a16e96098365f956:FZ-:zzzzzzzz
ba93090dfa64d964889f521788aca889:/.g:zzzzzzzz
c3bd6861732affa3a437df46a6295810:m}Z:zzzzzzzz
b31d9f86c28bd1245819817e353ceeb1:>)L:zzzzzzzzzzzz

在我的output.txt中,有8000万行像这样:

('chen123','45a36afe044ff58c09dc3cd2ee287164','','','','f+P',''),
('chen1234','45a36afe044ff58c09dc3cd2ee287164','','','','f+P',''),
('chen125','45a36afe044ff58c09dc3cd2ee287164','','','','f+P',''),

(45a36afe044ff58c09dc3cd2ee287164和f+p每行变化)

我所做的是创建一个简单的bash脚本来匹配cracked.txt和output.txt并加入它们。

cat './cracked.txt' | while read LINE; do
pwd=$(echo "${LINE}" | awk -F ":" '{print $NF}' | sed -e 's/x27/\\\x27/g' -e 's///\x2f/g' -e 's/x22/\\\x22/g' )
hash=$(echo "${LINE}" | awk -F ":" '{print $1}')
lines=$((lines+1))
echo "${lines} ${pwd}"
perl -p -i -e "s/${hash}/${hash} ( ${pwd} ) /g" output.txt
#sed -u -i "s/${hash}/${hash} ( ${pwd} ) /g" output.txt
done

正如您在评论中看到的,我已经尝试过sed和perl。perl似乎比sed快一点我每秒收到一行。

我从来没有使用过perl,所以我不知道如何利用它(多线程等)

加快这一进程的最佳方式是什么?

感谢

编辑:我得到了一个建议,最好使用这样的东西:

while IFS=: read pwd seed hash; do 
...
done < cracked.txt

但是,因为在第一次和最后一次出现:(awk'{print$1}'awk'{print$NF}',:之间可能会出现,这会使它变得糟糕(损坏它)我可以用它只是为了";hash";,但不适用于";pwd";。再次编辑;上面的方法不起作用,因为我必须命名所有其他数据,哪个ofc将是一个问题。

bash脚本的问题是,虽然它非常灵活和强大,但它几乎可以为任何东西创建新的进程,并且分叉成本很高。在循环的每个迭代中,生成3×echo、2×awk、1×sed和1×perl。将自己限制在一个进程中(从而限制在一种编程语言中)将提高性能。

然后,在对perl的调用中,您每次都在重读output.txt。IO总是很慢,所以如果你有内存的话,缓冲文件会更有效率。

如果没有散列冲突,多线程可以工作,但很难编程。与将Perl转换为多线程Perl相比,简单地转换为Perl将获得更大的性能提升[需要引文]

你可能会写一些类似的东西

#!/usr/bin/perl
use strict; use warnings;
open my $cracked, "<", "cracked.txt" or die "Can't open cracked";
my @data = do {
open my $output, "<", "output.txt" or die "Can't open output";
<$output>;
};
while(<$cracked>) {
my ($hash, $seed, $pwd) = split /:/, $_, 3;
# transform $hash here like "$hash =~ s/foo/bar/g" if really neccessary
# say which line we are at
print "at line $. with pwd=$pwdn";
# do substitutions in @data
s/Q$hashE/$hash ( $pwd )/ for @data;
# the Q...E makes any characters in between non-special,
# so they are matched literally.
# (`C++` would match many `C`s, but `QC++E` matches the character sequence)
}
# write @data to the output file

(未经测试或其他,无保证)

虽然这仍然是一个O(n²)解决方案,但它的性能会比bash脚本更好。请注意,当将@data组织到哈希树中时,它可以简化为O(n),并通过哈希代码进行索引:

my %data = map {do magic here to parse the lines, and return a key-value pair} @data;
...;
$data{$hash} =~ s/Q$hashE/$hash ( $pwd )/; # instead of evil for-loop

实际上,您将存储对数组的引用,该数组包含哈希树中包含哈希代码的所有行,因此前面的行宁愿是

my %data;
for my $line (@data) {
my $key = parse_line($line);
push @$data{$key}, $line;
}
...; 
s/Q$hashE/$hash ( $pwd )/ for @{$data{$hash}}; # is still faster!

另一方面,具有8E7 elems的散列可能并不完全执行良好。答案在于基准测试。

在解析我的工作日志时,我会这样做:为N个部分(N=num_processers)拆分文件;将拆分点对齐。启动N个线程来处理每个部分。工作非常快,但硬盘驱动器是瓶颈。

最新更新