为什么 Perl 给出 "Can't modify string in scalar output" 错误?

Why is Perl giving "Can't modify string in scalar output" error?

我是 Perl 的新手,这是我迄今为止最复杂的项目。如果我解释的任何部分没有意义或者我遗漏了什么,我深表歉意 - 我很乐意提供进一步的说明。只有一行代码导致了我的问题。

目标:

我有一个包含单列数据的文本文件。它是这样写的:

0
a,a,b,a
b,b,b,a
1
a,b,b,a
b,b,b,a

这样继续一个数字升序到15,每个数字后面的两行是四个a或b的组合,用逗号分隔。我已将此文件绑定到数组 @diplo,因此我可以指定其中的特定行。

我还有一个文件,其中包含两列数据 headers 我已将其转换为数组的散列(两列中的每一列都是一个数组)。哈希的名称是 $lookup,数组名称是标题的名称。实际数组仅从每列中不是标题的第一个值开始。该文件如下所示:

haplo           frequency
"|5,a,b,a,a|"   0.202493719
"|2,b,b,b,a|"   0.161139191
"|3,b,b,b,a|"   0.132602458

此文件包含 a 或 b 在四个位置的所有可能组合以及所有数字 0-14 及其相关频率。换句话说,它包括来自“|0,a,a,a,a|”的所有可能组合接下来是“|1,a,a,a,a|”一直到“|13,b,b,b,b|”和“|14,b,b,b,b|”。

我希望我的 Perl 代码遍历 @diplo 中以 a,a,b,a 开头的每个字母组合,并记录与包含 0-14 中每个数字的 haplo 数组的行关联的频率,例如首先记录与“|0,a,a,b,a|”相关的频率然后是“|1,a,a,b,a|”等等

输出应该是这样的:

0   #this is the number in the @diplo file and they increase in order from 0 up to 15
0.011     0.0023    0.003    0.0532    0.163    0.3421    0.128    0.0972    0.0869    0.05514    0.0219    0.0172    0.00824    0.00886    0.00196 #these are the frequencies associated with x,a,a,b,a where x is any number from 0 to 14.

我的代码: 这是我创建的 Perl 代码,希望能解决这个问题(如果需要,我可以 post 创建数组,但我不想 post 一大堆代码如果没有必要):

my $irow = 1;   #this is the row/element number in @diplo
my $lrow = 0;      #this is the row/element in $lookup{'haplo'}
my $copynumber = 0;
#print "$copynumber, $diplo[2]";
while ($irow < $diplolines - 1) {
  while ($copynumber < 15) {
    while ($lrow < $uplines - 1) {
      if ("|$copynumber,$diplo[$irow]|" = $lookup{'haplo'}[$lrow]) {  ##this is the only line that causes errors
        if ($copynumber == 0) {
          print "$diplo[$irow-1]\n"; 
          #print "$lookup{'frequency'}[$lrow]\t";
        }
        print "$lookup{'frequency'}[$lrow]\t"; 
      }
      $lrow = $lrow + 1;
    }
    $lrow = 0;
    $copynumber = $copynumber + 1;
  }
  $lrow = 0;
  $copynumber = 0;
  $irow = $irow + 1;
}

但是,行 if ("|$copynumber,$diplo[$irow]|" = $lookup{'haplo'}[$lrow]) 导致错误 Can't modify string in scalar assignment near "]) "。 我已经尝试在该行的各个元素周围添加语音标记、圆括号和 postrophes,但我仍然对这个错误有某种变体。我不确定如何解决此错误。

很抱歉问题很长,如有任何帮助,我们将不胜感激。

编辑:感谢关于 eq 的建议,它消除了错误,我现在比以前更了解 Perl。但是,即使我现在没有收到错误,如果我将任何内容放入此行的 if 循环中,例如打印一个数字,它不会被执行。如果我在 while 循环内但在 if 外放置相同的命令,它确实会被执行。我有严格和警告。有什么想法吗?

=是赋值,==是数值比较,eq是字符串比较。

您不能修改字符串:

$ perl -e 'use strict; use warnings; my $foo="def"; 
           if ("abc$foo" = "abcdef") { print "match\n"; } '      
Found = in conditional, should be == at -e line 1.
Can't modify string in scalar assignment at -e line 1, near ""abcdef") "
Execution of -e aborted due to compilation errors.

非数字字符串在数字比较中就像零:

$ perl -e 'use strict; use warnings; my $foo="def"; 
           if ("abc$foo" == 0) { print "match\n"; } '
Argument "abcdef" isn't numeric in numeric eq (==) at -e line 1.
match

字符串比较可能就是你想要的:

$ perl -e 'use strict; use warnings; my $foo="def"; 
           if ("abc$foo" eq "abcdef") { print "match\n"; } '
match

这是有问题的表达式:

"|$copynumber,$diplo[$irow]|" = $lookup{'haplo'}[$lrow]

等号 (=) 是赋值运算符。它将右侧的值分配给左侧的变量。因此,左边的操作数需要是一个变量,而不是这里的字符串。

我认为你根本不想在这里做作业。我认为您正在尝试检查是否相等。所以不要使用赋值运算符,使用比较运算符。

Perl 有两个相等比较运算符。 == 进行数字比较以查看其操作数是否相等,eq 进行字符串比较。为什么 Perl 需要两个运算符? Perl 会自动在字符串和数字之间进行转换,因此它不可能知道您想要进行哪种比较。所以你需要告诉它。

这两种比较有什么区别?好吧,考虑一下这段代码。

$x = '0';
$y = '0.0';

$x$y 相等吗?好吧,这取决于您进行的比较类型。如果将它们作为数字进行比较,那么,是的,它们是相同的值(无论是整数还是实数,零都是一样的)。但是如果你将它们作为字符串进行比较,它们是不同的(它们的长度一开始就不一样)。

所以我们现在知道以下内容

$x == $y # this is true as it's a numeric comparison
$x eq $y # this is false as it's a string comparison

那么让我们回到您的代码:

"|$copynumber,$diplo[$irow]|" = $lookup{'haplo'}[$lrow]

我猜你从这里开始 ==

"|$copynumber,$diplo[$irow]|" == $lookup{'haplo'}[$lrow]

但这不对,因为 |$copynumber,$diplo[$irow]| 显然是字符串,而不是数字。如果您尝试使用看起来不像数字的值进行数字比较,Perl 会给您一个警告。

因此您将其更改为 =,但这也不起作用,因为您现在已将其更改为作业。

你真正需要的是字符串比较:

"|$copynumber,$diplo[$irow]|" eq $lookup{'haplo'}[$lrow]