【问题标题】:Why does Perl string become undefined?为什么 Perl 字符串变得未定义?
【发布时间】:2014-01-01 06:47:37
【问题描述】:

将多个标量值连接成一个 Perl 字符串的正确方法是什么?

出于调试原因,以下代码故意是一系列语句。

my $bill_record;

$bill_record = $acct_no . " |";

$bill_record = $bill_record . defined($w_ptWtrMtrRecRef->{"mtr_addr_no"})  ?  $w_ptWtrMtrRecRef->{"mtr_addr_no"} : " "  . " |" ;

$bill_record = $bill_record . defined($w_ptWtrMtrRecRef->{"mtr_addr_str"}) ? $w_ptWtrMtrRecRef->{"mtr_addr_str"} : " " . " |" ;

$bill_record = $bill_record . defined($w_ptWtrMtrRecRef->{"mtr_addr_apt"}) ? $w_ptWtrMtrRecRef->{"mtr_addr_apt"} : " " . " |"  ;

$bill_record = $bill_record . $issue_date . " |";

| 字符用作分隔符。每行都将以'\n 终止。

最后一行之后$bill_record = $bill_record . $issue_date . " |"; 出现这个错误:

Use of uninitialized value $bill_record in concatenation (.) or string at /home/ics/include/WsBillFunc.pm line 1022.
 at /home/ics/include/WsBillFunc.pm line 1022

$issue_date 在分配时定义。

什么可能导致$bill_record 变得未定义,将一堆标量值连接成一个字符串的正确方法是什么?

【问题讨论】:

  • 首先使用$bill_record .= ... 而不是$bill_record = $bill_record . ... 会更容易阅读。另外,我会添加足够多的括号,以便操作顺序显而易见。
  • @woolstar 很好,但为什么呢?我认为采用原始标量 $bill_record 并使用 . 也可以。
  • 构建一个数组然后join(' |', ...)它可能也更干净,IMO 比一堆字符串连接更符合您的意图。
  • 您可能应该查找//= 运算符(及其相关运算符//)以及.=。它们允许您编写:$bill_record .= ($w_ptWtrMtrRecRef->{"mtr_addr_no"} // " ") . " |";,这比在页面的 RHS 上滚动的表达式更容易阅读。这确实假设您至少有 Perl 5.10,IIRC;但是你现在应该使用 5.18(或者如果你有逆行操作系统,可能是 5.16,比如 Mac OS X 10.9.1 Mavericks,它发布了 5.16.2)。
  • 你说的不是真的。发出该消息时,这不是您的代码,或者 $issue_date 未定义。

标签: string perl


【解决方案1】:

我不知道具体为什么 $bill_record 未定义。但是,如果我了解您要执行的操作,那么您将遇到优先级问题:?: 运算符的优先级低于串联.,因此

$bill_record = $bill_record . defined($w_ptWtrMtrRecRef->{"mtr_addr_no"})  ?  $w_ptWtrMtrRecRef->{"mtr_addr_no"} : " "  . " |" ;

被视为

$bill_record = ($bill_record . defined($w_ptWtrMtrRecRef->{"mtr_addr_no"}))  ?  $w_ptWtrMtrRecRef->{"mtr_addr_no"} : (" "  . " |") ;

我怀疑这不是你想要的。尝试添加括号:

$bill_record = $bill_record . (defined($w_ptWtrMtrRecRef->{"mtr_addr_no"})  ?  $w_ptWtrMtrRecRef->{"mtr_addr_no"} : " ")  . " |" ;

(或者按照另一位评论者的建议使用.=。)

【讨论】:

  • 非常有帮助。谢谢。我必须记住使用更多的括号。在这种情况下,我使用了.=,但您的回答也有助于解释原因。
  • 即使使用.=,您仍然需要括号,以便最后一个连接" " . " |" 不会优先于?:
【解决方案2】:

我可能会在一个声明中使用join

$bill_record = join ' |',
    map( {
        defined( $_ ) ? $_ : ' '
        } @{ $w_ptWtrMtrRecRef }{ qw( mtr_addr_no mtr_addr_str mtr_addr_apt ) }
        ),
    $issue_date,
    '';

map 中,我使用括号进行限制,因为我只想将它应用于哈希切片。之后是$issue_date 和空字符串。该空字符串将获得您拥有的最终|

但是,对于您的问题,您似乎有一个优先级问题。看到这一点的一种方法是让 Perl 编译然后解析你的程序,看看它认为你想要什么。 B::Deparse 模块执行此操作,我使用 -p 参数添加额外的括号。

这是原始程序的精简版本,在顶部添加了对解析器的调用(它是 B::Deparse 模块,但命名空间是 O

#!/usr/bin/perl

use O qw(Deparse -p);

my $b;
$b = $acct_no . " |";
$b = $b . defined($w->{"no"})  ? $w->{"no"}  : " " . " |" ;
$b = $b . defined($w->{"str"}) ? $w->{"str"} : " " . " |" ;
$b = $b . defined($w->{"apt"}) ? $w->{"apt"} : " " . " |"  ;
$b = $b . $issue_date . " |";

它输出:

my($b);
($b = ($acct_no . ' |'));
($b = (($b . defined($$w{'no'})) ? $$w{'no'} : '  |'));
($b = (($b . defined($$w{'str'})) ? $$w{'str'} : '  |'));
($b = (($b . defined($$w{'apt'})) ? $$w{'apt'} : '  |'));
($b = (($b . $issue_date) . ' |'));

关键部分是(($b . defined($$w{'no'}))。将$b的当前值与defined的返回值连接起来,然后条件运算符(? :)就完成了。如果测试值为真,则返回条件中的第一个值。

当它到达mgr_apt_no 时,可能有许多记录没有设置该值。但是,之前的$b$$w{'apt'} 的组合值是定义的,因为$b 不为空。因此,它选择$$w{'apt'} 的值分配给$b。当它执行最后一行时,$b$issue_date 的连接为空。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-12
    • 1970-01-01
    • 2018-09-29
    • 2013-09-17
    • 1970-01-01
    • 2015-12-20
    • 2015-11-08
    • 1970-01-01
    相关资源
    最近更新 更多