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

I'm almost embarassed to post this. Learning Perl from scratch, I'm happy with what I thought were going to be the difficult bits - I have a web-based system that is happily loading orders to and from a database using the appropriate modules. So far, so good.
Until I tried putting in an order which pushed the total line value stored over 1000. At which point, totalling up the line values to produce a grand total, I realised that all I was adding was 1 for 1000, 2 for 2000 etc. Numbers less than a thousand are fine.
OK, I know a bit about why it is failing, I think (although someone correct me if I am wrong). Perl is storing the numbers as scalars but with a thousands separator as a comma. Any time I try and use that, it thinks I am trying to read a list into a scalar and just grabs the first item, i.e. the number before the comma.
So if I have:
$mynum=2000.99;
$totalline = sprintf("%11.2f\n", $mynum);
all I get in $totalline is "2\n".
I'm using ActiveState Perl 5 on NT.
I have to be missing something here (apart from a Linux machine - but I don't think that would solve THIS problem) - someone embarass me by telling me what I am doing wrong?
Thanks
Martin GK
  • Comment on Thousands separator - this is getting annoying

Replies are listed 'Best First'.
Re: Thousands separator - this is getting annoying
by chipmunk (Parson) on Jan 16, 2001 at 22:59 UTC
    You've almost diagnosed the problem correctly, but not quite. When Perl turns the string "1,000" into a number, it does not think it is reading a list. What happens is that, since ',' is not a valid character in a number in Perl, the string-to-number conversion just stops when it gets to the comma. This would be the same as '1j000' or '1~000'.

    You don't show where your numbers are coming from, but you can avoid this problem by removing the commas from your 'numbers' before you use them as numbers: $num =~ tr/,//d; Of course, it would be simpler to not put the commas there in the first place.

      Thanks for the fast reply. Numbers are coming straight out of database in that form, so I don't get much choice in the matter! Will just regexp them as you suggest.
      Cheers
      Martin GK
        Why do who have a number field as a string in the db in the first place? You'll lose lots of db-side operations on numbers in this form.
        AgentM Systems nor Nasca Enterprises nor Bone::Easy nor Macperl is responsible for the comments made by AgentM. Remember, you can build any logical system with NOR.
        That doesn't make any sense, unless, as agentM suggest, your number field is represented internally as a string. While you might have some unusual reason for doing so, it's not a good idea.

        If possible, I'd put the burden of conversion on the database. Depending on what you're using, and how you're querying it, you might be able to use

        SELECT INT(field) FROM table

        -or-

        SELECT CONVERT(NUMERIC (10,2),field) FROM table

        good luck!

Re: Thousands separator - this is getting annoying
by mrmick (Curate) on Jan 16, 2001 at 23:10 UTC
    I tested your example:
    $mynum=2000.99; $totalline = sprintf("%11.2f\n", $mynum); print $totalline;
    and it gave me the following:
    2000.99
    If commas are giving you a problem, then you could quickly strip them out:
    s/,//g;
    This is probably not an ideal solution for you but I hope it does help in some way.

    To put the commas back, please refer to the How do I add commas to a number? node.

    Mick
      If commas are giving you a problem, then you could quickly strip them out:
      s/,//g;
      In a case like this, it's slightly better to use:
      tr/,//d;
        A very good point, particularly because I'd say the benefit is *much much* more than slight:
        use Benchmark; my $foo = join ',', ('bar') x 100; timethese(-10, { 's' => sub { (my $bar = $foo) =~ s/,//g }, 'tr' => sub { (my $bar = $foo) =~ tr/,//d }, });
        Results:
        Benchmark: running s, tr, each for at least 10 CPU seconds... s: 10 wallclock secs (10.00 usr + 0.00 sys = 10.00 CPU) @ 10 +150.70/s (n=101507) tr: 10 wallclock secs (10.01 usr + 0.00 sys = 10.01 CPU) @ 10 +9117.38/s (n=1092265)
        tr is 10 times faster here! A definite improvement.