0

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);

誰かが私に最も見栄えの良い解決策を教えていただければ幸いです。

4

3 に答える 3

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///

于 2011-03-10T16:07:21.543 に答える
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;
}

これは驚くほど簡単です。:)

于 2011-03-10T17:24:53.113 に答える
0

文字変換の代わりに置換を使用する短いサブルーチンを次に示します。

sub swap_digits {
    my ($str, $digit) = @_;
    $str =~ s{ (0) | $digit }{ defined $1 ? $digit : 0 }gex;
    return $str;
}
于 2011-03-10T17:19:01.230 に答える