当值可能是数字或字符串时,如何使用Perl的printf排列列?

时间:2010-04-15 06:46:28

标签: perl printf

我正在尝试输出一个看起来像这样的文档(更多信息来自http://pastebin.com/dpBAY8Sb):

     10.1.1.1       100   <unknown>              <unknown>              <unknown>         <unknown>         <unknown>
72.12.148.186        94   Canada                 Hamilton               ON                43.250000        -79.833300   0.00
72.68.209.149        24   United States          Richmond Hill          NY                40.700500        -73.834500   611.32
 72.192.33.34         4   United States          Rocky Hill             CT                41.657800        -72.662700   657.48

我找不到如何格式化输出我必须有一个浮点并格式化列之间的距离。我目前的代码看起来像这样。

if (defined $longitude){
   printf FILE ("%-8s %.6f","",$longitude);
}else{
 $longitude = "<unknown>";
   printf FILE ("%-20s ",$longitude);
} 

额外的""会抛出整个列,看起来像这样(http://pastebin.com/kcwHyNwb更多)。

10.1.1.1             100       <unknown>           <unknown>            <unknown>            <unknown>          <unknown>                 
72.12.148.186        94        Canada              Hamilton             ON                     43.250000         -79.833300           0.00
72.68.209.149        24        United States       Richmond Hill        NY                     40.700500         -73.834500           571.06

3 个答案:

答案 0 :(得分:2)

这些问题的诀窍是尽可能减少分支和重复的代码。 printf内置并不是那么特别。它需要一个格式参数和一个列表,所以你只需要给它正确的东西然后调用它一次。此外,通过使用Scalar::Utillooks_like_number之类的内容,您可以更精确地检查您的数据,以确保您的数据更接近您的预期:

use Scalar::Util qw(looks_like_number);

while( <DATA> ) 
    {
    chomp(my $longitude = $_ );

    my( $format, @arguments ) = do {
        looks_like_number $longitude ?
            ( "|%-8s %.6f|\n", '', $longitude )
              :
            ( "| %16s|\n",        '<unknown>' )
        };

    printf $format, @arguments;
    }

__END__
1
2.12345678
undef
0

fred

现在您有一个printf并且您不需要额外的$longitude2变量。 printf可以使用一些额外的技巧,因此您可以自动调整列的大小,但我们现在不会担心。 :)

答案 1 :(得分:1)

我认为你的未知格式字符串有点偏。

这是我的样本:

foreach $longitude (1,2.12345678,undef) {
  if (defined $longitude){
     printf ("|%-8s %.6f|\n","",$longitude);
  }else{
    $longitude2 = "<unknown>";
    printf ("| %16s|\n",$longitude2);
  } 
}

输出(" %16s"表示未知格式。我添加了垂直条以清楚地看到对齐方式):

|         1.000000|
|         2.123457|
|        <unknown>|

P.S。查看您的样本对齐与您生成的实际代码之间的关系,似乎状态<unknown>也可能是错误对齐的。要验证,请使用我在上面执行的相同技巧,将|中每个字段的格式字符串括起来,以查看一个字段的结束位置和另一个字段的开始位置。

答案 2 :(得分:0)

我个人会通过相同的printf传递它们

 # You can choose prefered way of laying out the logic !
     $text = sprintf ("%.6f",$longitude); 
 # or 
     $text = '<unknown>' ;

然后

 printf ("| %16s|\n",$text);

然后,如果16变为20,则两个位在步骤中适应。