带有插值的PERL5.26.1 eval tr运算符骆驼书第76页的示例不起作用

问题描述

尝试在tr运算符语句中将变量用作模式。 骆驼书第76页说要像这样使用eval:

eval "tr/$oldlist/$newlist/";

在Linux上使用perl_5.26.1时,有两点错误: a)如上使用引号eval会给出错误消息。 因此,您必须使用花括号将其放在一个块中。 b)即使在大括号中也不起作用。我究竟做错了什么?这是代码输出

    $kards = -99;
    $bad="AKQJT98765432KKKK";
    $card='K';
    eval {print "eval is testing for $card in $bad \n"; 
           $kards = $bad =~ tr/$card//; # tried also tr/$card/$card/; same result.
          };
    print "Num of $card in $bad = $kards \n";
    $king = $bad =~ tr/K//;
    print "Num of K in $bad is = $king \n";
=cut    
    Returns the following:
eval is testing for K in AKQJT98765432KKKK 
Num of K in AKQJT98765432KKKK = 0 
Num of K in AKQJT98765432KKKK is = 5 
    
=end 

解决方法

您想通过tr从字符串中删除一组字符,该字符集是在运行时确定的,并获取其中有多少个字符被删除了?

由于tr并没有像the documentation和您正在看的《 Programming Perl》书中所述进行变量插值,因此,必须将eval与字符串参数一起使用:

#!/usr/bin/env perl
use warnings;
use strict;
use feature qw/say/;

my $cards = "K";
my $str = "A12K34567890JQK";
my $count = eval "\$str =~ tr/$cards//";
say $count;

将产生2(在5.22或5.32上没有警告;在任何地方都没有安装5.26进行确认)。请注意,必须在字符串中对变量$进行操作的变量tr中转义eval,以便它不会首先被内插。


尽管如此,您可以使用s//来避免潜在危险的my $count = $str =~ s/[\Q$cards\E]//g; 的发生:

<html>
<body>

<p>Click the button to ask a question.</p>

<button onclick="myEightball()">I will answer any question</button>

<p id="eightball"></p>

<script>
function myEightball() {
  var text;
  var userQuestion = prompt("What would you like to know?");
  var randomNumber = Math.floor(Math.random()*8);
switch(randomNumber){
  case 1: 
  console.log('It is certain');
  text = 'It is certain';
  break;

  case 2: 
  console.log('It is decidely so');
  text = 'It is decidely so';
  break;

  case 3:
  console.log('Reply hazy try again');
  text = 'Reply hazy try again';
  break;

  case 4:
  console.log('Cannot predict now');
  text = 'Cannot predict now';
  break;

  case 5:
  console.log('Do not count on it');
  text = 'Do not count on it';
  break;

  case 6:
  console.log('My sources say no!');
  text = 'My sources say no!';
  break;

  case 7:
  console.log('Outlook is not good');
  text = 'Outlook is not good';
  break;

  case 0:
  console.log('Signs point to yes!');
  text = 'Signs point to yes!';
  break;
  
  default:
  console.log('Ask again later!');
  text = 'Ask again later!';
  break;
  }
  document.getElementById("eightball").innerHTML = text;
}
</script>

</body>
</html>