在tr ///中使用char变量

时间:2012-07-10 14:03:05

标签: perl

我正在尝试计算字符串中的字符,并找到一个使用tr运算符计算单个字符的简单解决方案。现在我想用从a到z的每个角色来做这个。以下解决方案不起作用,因为tr///匹配每个字符。

my @chars = ('a' .. 'z');
foreach my $c (@chars)
{
    $count{$c} = ($text =~ tr/$c//);
}

如何正确使用tr///中的char变量?

6 个答案:

答案 0 :(得分:7)

tr///不适用于变量,除非您将其包装在eval

但是有更好的方法可以做到这一点:

$count{$_} = () = $text =~ /$_/g for 'a' .. 'z';

对于TIMTOWTDI:

$count{$_}++ for grep /[a-z]/i, split //, $text;

答案 1 :(得分:6)

tr不支持变量插值(既不在搜索列表中也不在替换列表中)。如果要使用变量,则必须使用eval()

$count{$c} = eval "\$text =~ tr/$c/$c/";

也就是说,一种更有效(和安全)的方法是简单地遍历字符串中的字符并为每个字符增加计数器,例如:

my %count = map { $_ => 0 } 'a' .. 'z';

for my $char (split //, $text) {
    $count{$char}++ if defined $count{$char};
}

答案 2 :(得分:3)

如果您查看tr/SEARCHLIST/REPLACEMENTLIST/cdsr的{​​{3}},那么您会在本节底部看到以下内容:

  

由于音译表是在编译时构建的,因此SEARCHLIST和REPLACEMENTLIST都不会进行双引号插值。这意味着如果要使用变量,则必须使用eval():

eval "tr/$oldlist/$newlist/";
die $@ if $@;
eval "tr/$oldlist/$newlist/, 1" or die $@;

因此,您需要一个eval来生成一个新的SEARCHLIST。

这将是非常低效的......代码可能会感觉很整洁,但是你正在处理整个字符串26次。你也没有计算大写字符。

最好单步执行一次字符串,然后只为每个找到的字符递增计数器。

答案 3 :(得分:1)

来自perlop documentation

tr/AAA/XYZ/
     

会将任何A音译为X.

     

因为音译表是在编译时构建的,所以也不是   SEARCHLIST和REPLACEMENTLIST受到双重报价   插值。这意味着如果你想使用变量,你必须   使用eval()

或者在您的情况下,您可以使用s///运算符:

foreach my $c (@chars) {
   $count{$c} += ($text =~ s/$c//g);
}

答案 4 :(得分:1)

我的解决方案基于http://www.perlmonks.org/?node_id=446003

进行了一些修改
sub lowerLetters {
    my $string = shift;
    my %table;
    @table{split //, $letters_uc} = split //, $letters_lc;
    my $table_re = join '|', map { quotemeta } reverse sort keys %table;
    $string =~ s/($table_re)/$table{$1}/g;
    return if not defined $string;
    return $string;
}

答案 5 :(得分:0)

您可能想改用s。替代功能比tr

更强大

我的解决方案:

$count{$c} =~ s/\$search/$replace/g;

g的末尾表示“全局使用”。

请参阅: