我正在尝试计算字符串中的字符,并找到一个使用tr
运算符计算单个字符的简单解决方案。现在我想用从a到z的每个角色来做这个。以下解决方案不起作用,因为tr///
匹配每个字符。
my @chars = ('a' .. 'z');
foreach my $c (@chars)
{
$count{$c} = ($text =~ tr/$c//);
}
如何正确使用tr///
中的char变量?
答案 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)
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
的末尾表示“全局使用”。
请参阅: