首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >perl -通过查找数组从binmode字符串中删除字节。

perl -通过查找数组从binmode字符串中删除字节。
EN

Stack Overflow用户
提问于 2019-03-26 19:03:27
回答 1查看 152关注 0票数 1

我正在使用binmode()块读取文件,并希望删除与静态列表中任何值匹配的字节值。

代码语言:javascript
复制
@strip = (91,   92,   98,   107,   5,   64,   21,   13,   11,   12)

我在我的剧本里做什么

代码语言:javascript
复制
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

恐怕,这样做可能是不正确的,并有一些不良的结果。

有人能提出更清洁有效的替代方法来实现这一目标吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-03-26 19:24:10

regex引擎非常乐意在字节字符串上操作(尽管使用\d之类的操作可能没有任何意义),所以您的方法是非常好的。但是白色很有效率,它可以加速。

如果我们在字节上使用chr来剥离,而不是在读取的所有字符上使用ord呢?

代码语言:javascript
复制
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;

如果我们再往前走一步,更早地做出替代选择呢?

代码语言:javascript
复制
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;

但我们仍在做很多不必要的替换工作。如果我们搜索要替换的特定字符,该怎么办?

代码语言:javascript
复制
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;

这个速度要快得多,原因有三个:

  • 如前所述,我们大大减少了匹配的数量,这减少了替换表达式需要评估和连接的次数。
  • regex引擎可以比Perl代码更快地检查匹配的字符。
  • 我们消除了捕捉的需要,这是(相对来说)相当缓慢的。

请记住,@to_strip%to_strip%map$pat$re只需要计算一次,而不是每read计算一次。当我谈到上面提到的速度时,我并没有包括计算这些数据所需的时间,因为我假设您将进行多次读取和替换。

也就是说,如果硬编码要删除的字节是合理的,tr///d将为您提供最佳性能。

代码语言:javascript
复制
$data =~ tr/\x05\x0B-\x0D\x15\x40\x5B\x5C\x62\x6B//d;

从动态列表中使用tr///并不有效,因为tr///不插值。我们不得不建造一艘潜艇,而调用潜艇的速度相对较慢。

代码语言:javascript
复制
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);

以下是一种有效的(但肯定不是那么有效的)非正则表达式方法。

代码语言:javascript
复制
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
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55364557

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档