6

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

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

如何正确使用 char 变量tr///

4

6 回答 6

7

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

但是有一个更好的方法来做到这一点:

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

对于 TIMTOWDI:

$count{$_}++ for grep /[a-z]/i, split //, $text;
于 2012-07-10T14:12:26.497 回答
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};
}
于 2012-07-10T14:13:49.697 回答
3

如果您查看perldoc for tr/SEARCHLIST/REPLACEMENTLIST/cdsr,那么您会在该部分的底部看到以下内容:

因为音译表是在编译时构建的,所以 SEARCHLIST 和 REPLACEMENTLIST 都不受双引号插值的影响。这意味着如果要使用变量,则必须使用 eval():

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

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

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

您最好单步遍历字符串一次,然后为找到的每个字符增加计数器。

于 2012-07-10T14:13:38.703 回答
1

perlop 文档

tr/AAA/XYZ/

将任何 A 音译为 X。

因为音译表是在编译时构建的,所以 SEARCHLIST 和 REPLACEMENTLIST 都不受双引号插值的影响。这意味着如果要使用变量,则必须使用 eval()

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

foreach my $c (@chars) {
   $count{$c} += ($text =~ s/$c//g);
}
于 2012-07-10T14:13:24.927 回答
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;
}
于 2013-10-09T09:26:57.450 回答
1

您可能想s改用。替代的威力比tr

我的解决方案:

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

g最后的意思是“在全球范围内使用它”。

看:

于 2020-08-18T10:24:22.980 回答