higle has asked for the wisdom of the Perl Monks concerning the following question:

Wise Ones--

I've been pondering something, simple enough it would seem. In a project that I'm currently working on, I'm having to pull "dollar" values from a database that are formatted as floating point decimal numbers, and displaying them in currency format, replete with trailing zeros if there are none present. I've written a rather clunky block of code that gets the job done, but I know that there has to be a way to do this with a regular expression:

5.5 becomes $5.50
9 becomes $9.00
19.95 becomes $19.95 (unchanged, essentially)

All but the most elementary regular expressions are still my Achilles' Heel. My goal is to become a regular expression guru, but for now, the regex solution escapes me.

I humbly submit this, and eagerly await the masterful instruction.

Many thanks,
higle

Replies are listed 'Best First'.
Re: Dollars and regex cents
by VSarkiss (Monsignor) on Sep 06, 2001 at 22:04 UTC

    You don't need a regex, you need printf and the related sprintf:

    printf '$%.2f', 5.5; #prints $5.50 printf '$%.2f', 9; #prints $9.00 printf '$%.2f', 19.95; # print $19.95

    HTH

Re: Dollars and regex cents
by mexnix (Pilgrim) on Sep 06, 2001 at 22:05 UTC
    try sprintf:
    @nums = (5.5, 9, 19.95); print sprintf("\$%.2f\n", $_) foreach @nums;

    __________________________________________________

    s mmgfbs nf, nfyojy m,tr yb-zya-zy,s zfzphz,print;
    - thanks japhy :)

    mexnix.perlmonk.org

Re: Dollars and regex cents
by dragonchild (Archbishop) on Sep 06, 2001 at 22:02 UTC
    *laughs* You don't need a regex. You need simple CS 101 logic.
    my @values = ('5.5', '9', '19.95'); foreach my $value (@values) { my $dollars = int $value; my $cents = $value - $dollars; my $converted_value = sprintf "\$$dollars.%02d", int ($cents * 100 + + .5); print "$converted_value\n"; } ---- $5.50 $9.00 $19.95

    ------
    We are the carpenters and bricklayers of the Information Age.

    Vote paco for President!

Re: Dollars and regex cents
by higle (Chaplain) on Sep 06, 2001 at 22:40 UTC
    ::pouts::
    I guess regular expressions wait for another day. : )

    I didn't know that about sprintf, though. The elegant solution is at hand!

    Thanks, everyone, for all of your assistance!

    higle
      Here's a little code:
      sub dollars_cents { my $value = shift; my $comma = qq(,); my $count; my $dot = qq(.); my $dollar_sign = qq(\$); my @new_value; my $new_value; my @rvrs_value; my @value; $value =~ s/\D//g; @value = split (//,$value); @rvrs_value = reverse @value; push(@new_value, $rvrs_value[0]); shift @rvrs_value; push(@new_value, $rvrs_value[0]); shift @rvrs_value; push(@new_value, $dot); $count = 0; while (@rvrs_value) { if ($count eq 3) { push(@new_value, $comma); $count = 0; } else { push (@new_value, $rvrs_value[0]); shift @rvrs_value; $count++; } } push(@new_value, $dollar_sign); @new_value = reverse(@new_value); $new_value = join(//,@new_value); return($new_value); }

      Janitored by Arunbear - added code tags, as per Monastery guidelines

Re: Dollars and regex cents
by higle (Chaplain) on Sep 06, 2001 at 22:21 UTC
    Well, I solution that I'm using now is similar to Dragonchild's suggestion, using simple arithmetic and several assignments to achieve the same effect. The problem with using the printf and sprintf methods is that I'm storing the formatted value into a variable for use later, and not immediately printing it to standard output. O_o

    That's why I was hoping for a magical regex to come whisk the kludge from my code. I know it's possible, and it's driving me nuts!

    -hig

      Not a problem. Just take the routine and put it into a subroutine or method:

      sub convert_to_dollar_format { my $value = shift; $value += 0; # cheap error checking. You'll want something more robust return $value =~ /[^\d.]/ ? 0 : sprintf( '$%.2f', $value ); }

      With that sub, you just call it as you need it and don't worry about using the return value until necessary. Of course, you'll want to customize the error checking to fit your actual needs. Note that sprintf will not print the output (that was a concern you stated), but will merely format it properly).

      As for a regex solution, I wouldn't use one. Regexes are expensive in terms of performance and shouldn't be used if less expensive operations are available.

      Also, the reason you may want to update the error checking is due to it returning zero for non-numeric data. This is similar to Perl's handling of scalars, but probably is going to be harder to debug. I included the "add zero" line so the routine would warn about a non-numeric argument you if you have warnings enabled.

      Cheers,
      Ovid

      Vote for paco!

      Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

      As documented, sprintf returns a string you do not have to immediately print. You can just take the result of sprintf and store it in a variable.

      higle,
      using s?printf in this context is not a kludge at all! It's simply the most straightforward way to get the job done, we're functions meant for this purpose.

      Without thinking too much about it, I'd guess that a substitution regexp would require the e modifier to get the formatting job done. So it would be more cumbersome, more computationally expensive, harder to debug, probably uglier too :-)

      -- TMTOWTDI