我希望将数字从1 - 8音译为0但在编译时不知道数字。由于音译不插入变量,我这样做:
@trs = (sub{die},sub{${$_[0]} =~ tr/[0,1]/[1,0]/},sub{${$_[0]} =~ tr/[0,2]/[2,0]/},sub{${$_[0]} =~ tr/[0,3]/[3,0]/},sub{${$_[0]} =~ tr/[0,4]/[4,0]/},sub{${$_[0]} =~ tr/[0,5]/[5,0]/},sub{${$_[0]} =~ tr/[0,6]/[6,0]/},sub{${$_[0]} =~ tr/[0,7]/[7,0]/},sub{${$_[0]} =~ tr/[0,8]/[8,0]/});
然后将其索引为:
$trs[$character_to_transliterate](\$var_to_change);
如果有人能指出一个最好看的解决方案,我将不胜感激。
答案 0 :(得分:2)
任何时候你重复自己,你应该看看你在做什么可以循环完成。由于tr
在编译时创建表,因此可以使用eval
在运行时访问编译器:
my @trs = (sub {die}, map {eval "sub {\$_[0] =~ tr/${_}0/0$_/}"} 1 .. 8);
my $x = 123;
$trs[2]($x);
print "$x\n"; # 103
这里也没有必要使用引用,子程序参数已经通过引用传递。
如果您不想使用字符串eval,则需要使用支持运行时修改的构造。为此,您可以使用s///
运算符:
sub subst {$_[0] =~ s/($_[1]|0)/$1 ? 0 : $_[1]/ge}
my $z = 1230;
subst $z => 2;
print "$z\n"; # 1032
tr///
构造比s///
更快,因为后者支持正则表达式。
答案 1 :(得分:1)
我建议简单地放弃tr
支持一些实际上允许像s///
这样的元编程的东西。例如:
# Replace $to_swap with 0 and 0 with $to_swap, and leave
# everything else alone.
sub swap_with_0 {
my ($digit, $to_swap) = @_;
if ($digit == $to_swap) {
return 0;
} elsif ($digit == 0) {
return $to_swap;
} else {
return $digit;
}
}
# Swap 0 and $to_swap throughout $string
sub swap_digits {
my ($string, $to_swap) = @_;
$string =~ s/([0$to_swap])/swap_with_0($1, $to_swap)/eg;
return $string;
}
令人惊讶的直截了当。 :)
答案 2 :(得分:0)
这是一个使用替换而不是音译的简短子例程:
sub swap_digits {
my ($str, $digit) = @_;
$str =~ s{ (0) | $digit }{ defined $1 ? $digit : 0 }gex;
return $str;
}