我正在使用binmode()读取文件中的文件,并想去除与静态列表中的任何值匹配的字节值
@strip = (91, 92, 98, 107, 5, 64, 21, 13, 11, 12)
我在脚本中做什么
binmode($fh);
read($fh,$data,20);
%strip = (91=>1, 92=>1,98=>1,107=>1,5=>1,64=>1,21=>,13=>1,11=>1,12=>1);
$data=~s/(.)/$strip{ord($1)} ? "" :$1/ge
恐怕,以正则表达式方式执行操作可能不正确,并且会产生一些不良结果。
有人可以建议更清洁,高效的替代方法吗?
答案 0 :(得分:3)
regex引擎非常乐意对字节字符串进行操作(尽管使用\d
可能没有任何意义),因此您的方法非常好。但是白色非常有效,可以加快速度。
如果我们在字节上使用chr
而不是在所有读取的字符上使用ord
怎么办?
my @to_strip = ( 5, 11, 12, 13, 21, 64, 91, 92, 98, 107 );
my %to_strip = map { chr($_) => 1 } @to_strip;
$data =~ s/(.)/ $strip{$1} ? "" :$1 /ge;
如果我们走得更远,甚至更快地做出替换选择,该怎么办?
my @to_strip = ( 5, 11, 12, 13, 21, 64, 91, 92, 98, 107 );
my %to_strip = map { chr($_) => 1 } @to_strip;
my %map = map { $to_strip{$_} ? "" : $_ } map chr, 0x00..0xFF;
$data =~ s/(.)/$map{$1}/sg;
但是我们仍在进行许多不必要的替换。如果我们搜索要替换的特定字符怎么办?
my @to_strip = ( 5, 11, 12, 13, 21, 64, 91, 92, 98, 107 );
my $pat = "[" . quotemeta( pack( 'C*', @to_strip ) ) . "]+";
my $re = qr/$pat/;
$data =~ s/$re//g;
这个速度快得多有以下三个原因:
请记住,@to_strip
,%to_strip
,%map
,$pat
和$re
只需要计算一次,而不是每个read
一次。当我谈到上述速度时,我没有包括计算这些速度所需的时间,因为我认为您将进行多次读取和替换。
也就是说,如果合理地对要删除的字节进行硬编码,tr///d
将为您提供最佳性能。
$data =~ tr/\x05\x0B-\x0D\x15\x40\x5B\x5C\x62\x6B//d;
使用动态列表中的tr///
无效,因为tr///
不会插值。我们必须求助于构建一个sub,而调用sub相对较慢。
my @to_strip = ( 5, 11, 12, 13, 21, 64, 91, 92, 98, 107 );
my $class = quotemeta( pack( 'C*', @to_strip ) );
my $inline_stripper = eval("sub { $_[0] =~ tr/$class//d; }");
$inline_stripper->($data);
以下是一种有效(但肯定不那么有效)的非正则表达式方法。
my @to_strip = ( 5, 11, 12, 13, 21, 64, 91, 92, 98, 107 );
my @to_strip_lookup; $to_strip_lookup[$_] = 1 for @to_strip;
$data = pack 'C*', grep !$to_strip_lookup[$_], unpack 'C*', $data