Движок регулярных выражений идеально подходит для работы со строками байтов (хотя использование \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;
Этот намного быстрее по трем причинам:
- Как упоминалось ранее, мы значительно сократили количествосовпадений, что уменьшает количество раз, когда выражение замены необходимо оценивать и объединять.
- Механизм регулярных выражений может проверять совпадения символов гораздо быстрее, чем наш код Perl.
- Мы устранили необходимостьдля захватов, которые (условно говоря) довольно медленные.
Помните, что @to_strip
, %to_strip
, %map
, $pat
и $re
нужно вычислять только один раз, а неодин раз за read
.Когда я говорил о скорости выше, я не учитывал время, необходимое для их вычисления, так как я предполагал, что вы будете выполнять несколько операций чтения и замены.
При этом было бы разумно жестко закодировать байтычтобы удалить, tr///d
даст вам лучшую производительность.
$data =~ tr/\x05\x0B-\x0D\x15\x40\x5B\x5C\x62\x6B//d;
Неэффективно использовать tr///
из динамического списка, потому что tr///
не интерполирует.Мы должны прибегнуть к созданию подпрограммы, и вызов подпрограммы является относительно медленным.
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