【问题标题】:in perl, why does sprintf(Dumper \%hash) throw a warning when the hash contains a long string?在 perl 中,当哈希包含长字符串时,为什么 sprintf(Dumper \%hash) 会抛出警告?
【发布时间】:2021-07-23 13:56:43
【问题描述】:

几个月来我一直在使用如下语法,但没有触发警告:

die join('', sprintf(Dumper [@stack]), sprintf(Dumper {%oprAtnNOW}), 'opt tojudge not specified');

也就是说,我使用sprintfDumper,没有指定格式。

在下面的代码中,我们看到这可以正常工作,但只能达到一定程度。%oprAtnNOW 包含长字符串时,会触发警告。 (在所有情况下,字符串都编译为正则表达式;但在编译之前,它只是一个字符串。)

长字符串警告的原因是什么?为什么会有“缺失的论点”? 当然,sprintf 应该被赋予一种格式,如 https://perldoc.perl.org/functions/sprintf。 但是为什么只有在将较小的字符串替换为长字符串时才强制执行此操作?

#!/usr/bin/perl
use strict; use warnings;
use Data::Dumper qw(Dumper);
$Data::Dumper::Sortkeys = 1;
print "Perl version: $^V\n";

my %oprAtnNOW; 
my $string='~~~~~1983-10-21 Fri 13:01:13, today we went to the movie.';

%oprAtnNOW = (
    Vv => {
        v=>[ '(?<a>a)',],
    },
);

tryit();

%oprAtnNOW = (
    Vv => {
        v=>[ 
'(?m)^(?<boundjour2009>(?<tilde5>[~]{5})[\\x20\\t]*(?<dateISO1mbeWeekdaymbeTIME>(?<dateISO1mbeWeekday>(?<dateISO1>(?<YYYY>[1-9]\\d\\d\\d)[-](?<nMonth2>0[1-9]|1[0-2])[-](?<nMonthDay2>3[01]|[0-2][0-9]))([\\x20\\t]+(?<wWeekdayAllor3>Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sun|Mon|Tue|Wed|Thu|Fri|Sat))?)([\\x20\\t]+(?<nTIMEdiverse>(at[\\x20\\t]+)?((?<HHcMMcSS>(?<HH>0[0-9]|1[0-9]|2[0-3]):(?<MM>[0-5][0-9]):(?<SS>[0-5][0-9]))|(?<HHMMmbeSS>(?<HHMM>(?<HH>0[0-9]|1[0-9]|2[0-3])(?<MM>[0-5][0-9]))(?<SS>[0-5][0-9])?)|(?<HHcMM_pct_cSS>(?<HH>0[0-9]|1[0-9]|2[0-3]):(?<MM>[0-5][0-9])%:(?<SS>[0-5][0-9]))|(?<HHcMM_stop>(?<HH>0[0-9]|1[0-9]|2[0-3]):(?<MM>[0-5][0-9])(?![:][0-5][0-9])))))?))',
        ],
    },
);

tryit();

sub tryit
{
    my $rgx=qr/$oprAtnNOW{Vv}->{v}->[0]/;
    if($string=~$rgx)
    {
        print Dumper \%+;
    }
    print "with format:\n";
    print sprintf('%s', Dumper \%oprAtnNOW); 
    print "WITHOUT format:\n";
    print sprintf(Dumper \%oprAtnNOW); 
}

输出:

Perl version: v5.18.4
$VAR1 = {
          'a' => 'a'
        };
with format:
$VAR1 = {
          'Vv' => {
                    'v' => [
                             '(?<a>a)'
                           ]
                  }
        };
WITHOUT format:
$VAR1 = {
          'Vv' => {
                    'v' => [
                             '(?<a>a)'
                           ]
                  }
        };
$VAR1 = {
          'HH' => '13',
          'HHcMMcSS' => '13:01:13',
          'MM' => '01',
          'SS' => '13',
          'YYYY' => '1983',
          'boundjour2009' => '~~~~~1983-10-21 Fri 13:01:13',
          'dateISO1' => '1983-10-21',
          'dateISO1mbeWeekday' => '1983-10-21 Fri',
          'dateISO1mbeWeekdaymbeTIME' => '1983-10-21 Fri 13:01:13',
          'nMonth2' => '10',
          'nMonthDay2' => '21',
          'nTIMEdiverse' => '13:01:13',
          'tilde5' => '~~~~~',
          'wWeekdayAllor3' => 'Fri'
        };
with format:
$VAR1 = {
          'Vv' => {
                    'v' => [
                             '(?m)^(?<boundjour2009>(?<tilde5>[~]{5})[\\x20\\t]*(?<dateISO1mbeWeekdaymbeTIME>(?<dateISO1mbeWeekday>(?<dateISO1>(?<YYYY>[1-9]\\d\\d\\d)[-](?<nMonth2>0[1-9]|1[0-2])[-](?<nMonthDay2>3[01]|[0-2][0-9]))([\\x20\\t]+(?<wWeekdayAllor3>Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sun|Mon|Tue|Wed|Thu|Fri|Sat))?)([\\x20\\t]+(?<nTIMEdiverse>(at[\\x20\\t]+)?((?<HHcMMcSS>(?<HH>0[0-9]|1[0-9]|2[0-3]):(?<MM>[0-5][0-9]):(?<SS>[0-5][0-9]))|(?<HHMMmbeSS>(?<HHMM>(?<HH>0[0-9]|1[0-9]|2[0-3])(?<MM>[0-5][0-9]))(?<SS>[0-5][0-9])?)|(?<HHcMM_pct_cSS>(?<HH>0[0-9]|1[0-9]|2[0-3]):(?<MM>[0-5][0-9])%:(?<SS>[0-5][0-9]))|(?<HHcMM_stop>(?<HH>0[0-9]|1[0-9]|2[0-3]):(?<MM>[0-5][0-9])(?![:][0-5][0-9])))))?))'
                           ]
                  }
        };
WITHOUT format:
Missing argument in sprintf at /Users/kpr/u/kh/bin/z.pl line 38.
Invalid conversion in sprintf: "%:" at /Users/kpr/u/kh/bin/z.pl line 38.
$VAR1 = {
          'Vv' => {
                    'v' => [
                             '(?m)^(?<boundjour2009>(?<tilde5>[~]{5})[\\x20\\t]*(?<dateISO1mbeWeekdaymbeTIME>(?<dateISO1mbeWeekday>(?<dateISO1>(?<YYYY>[1-9]\\d\\d\\d)[-](?<nMonth2>0[1-9]|1[0-2])[-](?<nMonthDay2>3[01]|[0-2][0-9]))([\\x20\\t]+(?<wWeekdayAllor3>Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sun|Mon|Tue|Wed|Thu|Fri|Sat))?)([\\x20\\t]+(?<nTIMEdiverse>(at[\\x20\\t]+)?((?<HHcMMcSS>(?<HH>0[0-9]|1[0-9]|2[0-3]):(?<MM>[0-5][0-9]):(?<SS>[0-5][0-9]))|(?<HHMMmbeSS>(?<HHMM>(?<HH>0[0-9]|1[0-9]|2[0-3])(?<MM>[0-5][0-9]))(?<SS>[0-5][0-9])?)|(?<HHcMM_pct_cSS>(?<HH>0[0-9]|1[0-9]|2[0-3]):(?<MM>[0-5][0-9])%:(?<SS>[0-5][0-9]))|(?<HHcMM_stop>(?<HH>0[0-9]|1[0-9]|2[0-3]):(?<MM>[0-5][0-9])(?![:][0-5][0-9])))))?))'
                           ]
                  }
        };

【问题讨论】:

  • 你为什么要在已经是字符串的东西上使用sprintf,即Dumper的输出?这似乎非常不必要。

标签: perl data-dumper


【解决方案1】:

不是因为长度,而是因为长字符串包含百分号。

...(?<MM>[0-5][0-9])%:(?<SS>[0-5][0-9]))...
                    ~

因为它是唯一的参数,所以它被解释为格式。

您可以使用更短的字符串来演示相同的行为,例如

sprintf '%';

如果不需要格式化,就用print

print Dumper \%oprAtnNOW; 

【讨论】:

  • 你应该提一下,这种方式使用sprintf不是很有用,而且容易出bug。
  • @choraba,您是如何在代码 sn-p 中获得百分号下方的波浪号的?
  • @JacobWegelin 就在下面一行。
  • @TLP 有什么办法,特别是?我需要生成错误消息,准确地告诉我我在代码中的位置以及发生故障时的结构(数组、哈希)是什么。所以我使用 join 和 sprintf 来创建我的错误消息。还有其他方法我应该这样做吗?这样,我不必为单个错误发出多个打印 STDERR 命令。请参阅我原始帖子开头的示例错误消息。
  • @JacobWegelin Dumper 是一个返回字符串的函数。同样的方式sprintf 返回一个字符串。您实际上可以不使用sprintf,您的代码将正常工作。
猜你喜欢
  • 1970-01-01
  • 2015-09-30
  • 2012-03-30
  • 1970-01-01
  • 2012-09-29
  • 2011-06-14
  • 2014-09-25
  • 1970-01-01
  • 2014-11-26
相关资源
最近更新 更多