Thursday, March 31, 2011

How can I render undefined values from printf in Perl?

I'm looking for an elegant way to denote undefined values in situations where formatted numbers usually render. I'll work up a small example. For starters, you of course can't use this:

#!/usr/bin/perl
use strict;
use warnings;
for my $s (1, 1.2, undef, 1.3) {
    printf "%5.2f\n", $s;
}

...because the 'use warnings' nails you with 'Use of uninitialized value...' on the third iteration. So the next step is something like this:

#!/usr/bin/perl
use strict;
use warnings;
for my $s (1, 1.2, undef, 1.3) {
    printf "%5.2f\n", $s//0;
}

And, boy, do I like the new 5.10 '//' operator, by the way. But that's really not what I want, either, because the value of $s isn't zero, it's undefined. What I really want is something like this:

#!/usr/bin/perl
use strict;
use warnings;
for my $s (1, 1.2, undef, 1.3) {
    printf "%5.2f\n", $s//q();
}

...but I can't because this generates the "Argument "" isn't numeric..." problem on the third value.

This brings me to the doorstep of my question. I can of course write code that checks every number I emit for defined-ness, and that creates a whole different non-%f-based printf format string, but, well, ...yuck.

Has anyone defined a nice way to deal with this type of requirement?

From stackoverflow
  • It's not pretty, but I'd just do it as

    defined($s) ? printf "%f.2f\n", $s : print "undef\n";
    
  • I don't think there's anything yuck about it -- it's exactly what you want to do.

    use strict;
    use warnings;
    
    my($raw) = [1, 1.2, undef, 1.3];
    my($formatted) = [map((defined $_ ? sprintf('%5.2f', $_) : "(undef)"), @$raw)];
    
    print '$formatted: <', join('> <', @{$formatted}), qq(>\n);
    
  • I think the nice way is to write/get a generic prettyprinter that takes whatever you throw at it and then do:

    #!/usr/bin/perl
    use strict;
    use warnings;
    use MyPrettyPrinter;
    for my $s (1, 1.2, undef, 1.3) {
        print MyPrettyPrinted($s), "\n";
    }
    

0 comments:

Post a Comment