我正在尝试计算字符串中的字符,并找到了一个使用tr
运算符计算单个字符的简单解决方案。现在我想对从 a 到 z 的每个字符执行此操作。以下解决方案不起作用,因为tr///
匹配每个字符。
my @chars = ('a' .. 'z');
foreach my $c (@chars)
{
$count{$c} = ($text =~ tr/$c//);
}
如何正确使用 char 变量tr///
?
我正在尝试计算字符串中的字符,并找到了一个使用tr
运算符计算单个字符的简单解决方案。现在我想对从 a 到 z 的每个字符执行此操作。以下解决方案不起作用,因为tr///
匹配每个字符。
my @chars = ('a' .. 'z');
foreach my $c (@chars)
{
$count{$c} = ($text =~ tr/$c//);
}
如何正确使用 char 变量tr///
?
tr///
除非您将其包装在变量中,否则不适用于变量eval
但是有一个更好的方法来做到这一点:
$count{$_} = () = $text =~ /$_/g for 'a' .. 'z';
对于 TIMTOWDI:
$count{$_}++ for grep /[a-z]/i, split //, $text;
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};
}
如果您查看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 次。你也没有计算大写字符。
您最好单步遍历字符串一次,然后为找到的每个字符增加计数器。
tr/AAA/XYZ/
将任何 A 音译为 X。
因为音译表是在编译时构建的,所以 SEARCHLIST 和 REPLACEMENTLIST 都不受双引号插值的影响。这意味着如果要使用变量,则必须使用 eval()
或者,在您的情况下,您可以将s///
运算符用作:
foreach my $c (@chars) {
$count{$c} += ($text =~ s/$c//g);
}
我的解决方案基于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;
}
您可能想s
改用。替代的威力比tr
我的解决方案:
$count{$c} =~ s/\$search/$replace/g;
g
最后的意思是“在全球范围内使用它”。
看: