我正在尝试输出一个看起来像这样的文档(更多信息来自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
答案 0 :(得分:2)
这些问题的诀窍是尽可能减少分支和重复的代码。 printf内置并不是那么特别。它需要一个格式参数和一个列表,所以你只需要给它正确的东西然后调用它一次。此外,通过使用Scalar::Util的looks_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,则两个位在步骤中适应。