in reply to using tr

Here are a couple of other approaches. The  s/// operation will be significantly slower than  tr// for very long strings (for some definition of 'very long').

(And yes, please do edit the OP to use code tags. Please see Markup in the Monastery and Writeup Formatting Tips.)

>perl -wMstrict -le "my @ranges = ([33..42], [43..52], [53..62], [63..126]); ;; my $chars = join '', map { map chr, @$_ } @ranges; $chars =~ s{\\}'\\\\'xms; $chars =~ s{/}'\/'xms; ;; my $bins = join '', map { $_ x @{$ranges[$_]} } 0 .. $#ranges - 1; $bins .= $#ranges; ;; print qq{'$chars'}; print qq{'$bins'}; ;; eval qq{ sub binned { (my \$t = \$_[0]) =~ y/$chars/$bins/; return \$t; } }; ;; my $test = qq[!\x22 )#+, 3456 =>?@ }~]; print qq{test string: '$test'}; printf qq{tr// method: '%s' \n}, binned($test); ;; ;; my %xlate = map { my $i = $_; map { chr() => $i } @{$ranges[$_]} } 0 .. $#ranges ; ;; $test =~ s{(.)}{ exists $xlate{$1} ? $xlate{$1} : $1 }xmsge; print qq{s/// method: '$test'}; " '!"#$%&'()*+,-.\/0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abc +defghijklmnopqrstuvwxyz{|}~' '0000000000111111111122222222223' test string: '!" )#+, 3456 =>?@ }~' tr// method: '00 0011 1122 2233 33' s/// method: '00 0011 1122 2233 33'

Updates:

  1. Improved example code slightly: removed MS-reactive " (double-quote) characters from source; better printout labeling, formatting.
  2. In the last  s/// statement, the  exists $xlate{$1} ? $xlate{$1} : $1 expression can be replaced by  $xlate{$1} // $1 in 5.10+ for possibly slightly faster execution (not Benchmarked).