Perl's tr/// is not doing what I want
EDIT: tr/// does not support variable interpolation, so I went with s/\Q$_\E//g;
instead
Or, more likely, I'm not doing something right...
I have the following code:
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
sub strip_i开发者_StackOverflow中文版nvalid {
my ($str, @chars) = @_;
map { $str =~ tr/$_//; } @chars;
return $str;
}
my @invalid = qw( a e i o u );
print strip_invalid("This is the super sample with vowels.\n", @invalid);
I'd just like to pass a string to strip_invalid()
and have tr///
remove the characters in @invalid
through a map
... Where did I go wrong? (by the way, using regular expressions it works).
Perl's tr
feature doesn't support variables.
Note that because the translation table is built at compile time, neither the SEARCHLIST nor the REPLACEMENTLIST are subjected to double quote interpolation. That means that if you want to use variables, you must use an eval():
eval "tr/$oldlist/$newlist/";
(Source)
Since tr///
does not allow the use of variables, I would suggest something along these lines (rather than using eval
, which raises other concerns):
sub strip_invalid {
my $str = shift;
my $chars = quotemeta(join '', @_);
$str =~ s/[$chars]//g;
return $str;
}
Note also that tr///
has a delete option, so it's not necessary to iterate across all characters that you want to delete. For example:
$str =~ tr/aeiou//d; # Delete all vowels from $str
To delete with tr, you need to specify the /d flag. Otherwise, it defaults the replacementlist based on the searchlist (so just counts or compresses).
And tr does not support variable interpolation.
To use tr, you'd need to do something like this:
sub strip_invalid {
my ($str, @chars) = @_;
my $strip = quotemeta join '', @chars;
eval "\$str =~ tr/$strip//d";
return $str;
}
精彩评论