如何使用Perl格式编写科学记数法?

时间:2010-09-14 19:32:41

标签: perl format printf

我一直使用printf,而我从未使用write / format。有没有办法使用格式重现printf("%12.5e", $num)?我在消化perlform documentation时遇到了麻烦,但我没有看到这样做的简单方法。

编辑:基于我得到的答案,我将继续使用printf。

2 个答案:

答案 0 :(得分:2)

简短回答,不要使用格式。

未经检索的答案,当然,只需使用sprintf

#!/usr/bin/perl

use strict;
use warnings;

our $num = .005;

write;

format STDOUT =
@>>>>>>>>>>>>>>>>>
sprintf("%12.5e", $num)
.

说真的,如果你需要类似Perl 5格式的东西,请看一下Perl6::Form(注意,这是一个Perl 5模块,它只是实现了建议的Perl 6格式版本)。

答案 1 :(得分:2)

我完全赞同Chas。欧文斯的格式一般。 Format 15年前非常光滑,但format没有跟上Perl其他部分的进步。

这是我不时使用的面向行的输出技术。您可以使用formline,它是format使用的公共内部函数之一。 Format面向页面。执行诸如跨度列之类的操作或根据数据按行更改格式非常困难。您可以使用format使用的相同文本格式逻辑格式化单行,然后自己输出该结果。

一个(凌乱)的例子:

use strict; use warnings;

sub print_line {
    my $pic=shift;
    my @args=@_;

    formline($pic,@args);
    print "$^A\n";
    $^A='';
}

my ($wlabel, $wlow, $whigh, $wavg)=(0,0,0,0);
my ($plabel,$plow,$phigh, $pavg);
my ($s_low,$s_high,$s_avg)=qw(%.2f %.2e %.2f);


my @results=( ["Label 1", 3.445, 0.00006678, .025],
           ["Label 2", 12.5555556, 55.112, 1.11],
           ["Wide Label 3", 1231.11, 1555.0, 66.66] );

foreach (@results) { 
    my $tmp;
    $tmp=length($_->[0]);
    $wlabel=$tmp if $tmp>$wlabel; 

    $tmp=length(sprintf($s_low,$_->[3]));
    $wlow=$tmp if $tmp>$wlow;

    $tmp=length(sprintf($s_high,$_->[2]));
    $whigh=$tmp if $tmp>$whigh;

    $tmp=length(sprintf($s_avg,$_->[1]));
    $wavg=$tmp if $tmp>$wavg;
}

print "\n\n";
my @a1=("Label", "Rate - Operations / sec");
my @a2=("Text", "Average", "High", "Low");
my @a3=("----------", "-------", "----", "---");
my $l1fmt="@".'|' x $wlabel."   @".'|'x($whigh+$wavg+$wlow+6);

my $l2fmt="@".'|' x $wlabel."    @".'|' x $wavg."   @".'|' x $whigh . 
           "   @".'|' x $wlow;
print_line($l1fmt,@a1);
print_line($l2fmt,@a2);
print_line($l2fmt,@a3);

$plabel="@".'>' x $wlabel;
$phigh="@".'>' x $whigh;
$pavg="@".'>' x $wavg;
$plow="@".'<' x $wlow;


foreach (@results) {
    my $pic="$plabel   $pavg   $phigh   $plow";
    my $mark=$_->[0];
    my $avg=sprintf($s_avg,$_->[1]);
    my $high=sprintf($s_high,$_->[2]);
    my $low=sprintf($s_low,$_->[3]);
    print_line($pic,$mark,$avg,$high,$low);
}
print "\n\n";

输出:

    Label         Rate - Operations / sec
    Text         Average      High       Low
 ----------      -------      ----       ---
      Label 1       3.44    6.68e-05   0.03
      Label 2      12.56    5.51e+01   1.11
 Wide Label 3    1231.11    1.56e+03   66.66

请注意,列的宽度是根据sprintf格式字符串格式化的数据宽度设置的。然后,您可以左,中,右对齐该结果。 “低”数据列左对齐,其余数据右对齐。您可以通过标量$plow中使用的符号对其进行更改,它与format语法相同。顶部的标签居中,“Rate - Operations / sec”标签跨越3列。

这显然不是“生产就绪”代码,但我认为你会有所偏差。您需要根据所需宽度等进一步检查列的总宽度。您必须手动执行格式化的一些工作,但您可以使用此方法获得更大的灵活性。例如,对于sprintf的行的几个部分,使用此方法非常容易。

干杯。