tags:

views:

221

answers:

3

I am trying to output a document that looks like this (more at 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

I cannot find how to format the output I have to have a floating poing and format the distance between columns. My current code looks something like this.

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

The extra "" throws off the whole column and it looks like this (more at 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
+1  A: 

I think your format string for unknown is a bit off.

Here's my sample:

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

And the output (with " %16s" for unknown format. I added vertical bars to see alignment clearly):

|         1.000000|
|         2.123457|
|        <unknown>|

P.S. Looking at your sample alignment vs. what the actual code you produced, it seems that the state <unknown> is also possibly mis-aligned. To verify, use the same trick I did above, enclosing the format string for each field in | to see where one field ends and another begins.

DVK
+2  A: 

The trick in these problems is to reduce the branching and duplicated code as much as possible. The printf built-in isn't that special. It takes a format argument and a list, so you just need to give it the right things then call it once. Also, you can be more precise with your check by using something like Scalar::Util's looks_like_number to ensure your data are closer to what you expect:

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

Now you have one printf and you don't need an extra $longitude2 variable. There are some extra tricks you can play with printf so you can automatically size the columns, but we won't worry about that right now. :)

brian d foy
A: 

Personally I would pass them throught the same printf

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

and then

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

Then if the 16 becomes 20 both bits adapt in step.

justintime