views:

84

answers:

3

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_invalid {
  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).

+6  A: 

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)

Mark Byers
+4  A: 

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
FM
+2  A: 

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;
}
ysth