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

Hi, Someone on the gtk2 perl maillist was asking a question about number text returned from a label, being in European and commafied format, and not acting as a number,

Well I thought, this ought to be easy with a tr or regex, but it isn't. So before I blow my mind on Friday, I figure I would ask about this.

The code below, takes a float, converts it to European format, then I attempt, to tr ( or regex ) the comma's out. I keep losing the digit 7. ???? I can't make any sense why, although I did find a clunky way (shown below).

Can the regex experts explain what is happening?

#!/usr/bin/perl my $num_in = 1234567.89; print "$num_in\n"; my $num_out = scalar reverse join "", map { s/(\d{2})\./$1,\b/; s/^(\d{1,3})$/\.$1/; + $_ } (reverse sprintf("%.2f", $num_in)) =~ m/.{1,3}/g; print "$num_out\n"; my $get_text = $num_out; print "$get_text\n"; #this loses the 7 # $get_text =~ s/\.//g; # tr is similar $get_text =~ tr/.//d; #this clunky method works to remove commas # $get_text =~ s/\./ /g; # # $get_text =~ s/\s+//g; #won't work to remove spaces # $get_text =~ s/\s+//; # $get_text =~ s/\s+//; #this then works to change decimal point to . $get_text =~ tr/,/./d; # now if I try to force numeric context it fails #$get_text = $get_text + 0.00; print "$get_text\n";

I'm not really a human, but I play one on earth. Cogito ergo sum a bum

Replies are listed 'Best First'.
Re: disappearing digit with regex and tr
by ikegami (Patriarch) on Aug 18, 2006 at 15:04 UTC
    I don't know why (don't have time to find out), but you're printing a backspace.
    Before the s///: length = 14 31 2e 32 33 34 2e 35 36 37 2e 08 2c 38 39 1 . 2 3 4 . 5 6 7 . ^H , 8 9 After the s///: length = 11 31 32 33 34 35 36 37 08 2c 38 39 1 2 3 4 5 6 7 ^H , 8 9

    Update: It's the \b. \b means backspace in a string literal.

    Update: Here's a quickly written solution:

    my $num_in = 1234567.89; my ($i, $d) = split /\./, $num_in; $i = reverse($i); $i =~ s/\G(\d{3})(?!$)/$1./g; $i = reverse($i); my $num_out = "$i,$d"; print($num_out, "\n");
Re: disappearing digit with regex and tr
by Velaki (Chaplain) on Aug 18, 2006 at 15:13 UTC

    After running your snippet of code and piping it through cat -v, I get:

    1234567.89 1.234.567.^H,89 1.234.567.^H,89 1234567^H.89
    It looks like you have a remnant of a word boundry in your regex in that long statement, but because it's in the replacement side of the substitution, it's being treated as a backspace. Perhaps you meant it to go in the search portion of the substitution section?

    Hope this helped,
    -v.

    "Perl. There is no substitute."
Re: disappearing digit with regex and tr
by duff (Parson) on Aug 18, 2006 at 15:06 UTC

    I'd say it has something to do with that backspace you're inserting into the string in the first substitution of your map. Don't do that :-)

    you can see that the missing 7 is really still there by piping the output of your program through some utility like xxd to get a raw dump.

Re: disappearing digit with regex and tr
by zentara (Cardinal) on Aug 18, 2006 at 15:45 UTC
    Thanks. I'll have to wait till tommorrow to upvote you guys, I'm all out today. I guess I deserve what I got for not checking that map carefully. Sneaky backspace.

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum
Golf, anyone? :)
by suaveant (Parson) on Aug 18, 2006 at 17:40 UTC
    perl -e '$_=1234567;s/\./,/;s/(?=(\d\d\d)+(,|\Z))/./g;print'

                    - Ant
                    - Some of my best work - (1 2 3)

      perl -e '$_=1234567;s/\./,/;s/(?=(\d\d\d)+(,|\Z))/./g;print'

      That doesn't handle 234567 nor 234567.89 too well. :)

      My best, based on yours, obviously:

      y/./,/;s/\d(?=(\d\d\d)+(,|\Z))/$&./g; # 37, counting the semicolon

      Update: Ow, too obviously. \Z is just long-hand for $ ... so slice one off ... and update2 \d\d\d can be shortened to \d{3} for one more:

      y/./,/;s/\d(?=(\d{3})+(,|$))/$&./g; # 35, counting the semicolon
      ... or, to demonstrate ...
      sidhekin@blackbox:~$ perl -le 'for (@ARGV) { y/./,/;s/\d(?=(\d{3})+(,| +$))/$&./g;print }' 1234567.89 234567.89 1234567 234567 1.234.567,89 234.567,89 1.234.567 234.567 sidhekin@blackbox:~$

      print "Just another Perl ${\(trickster and hacker)},"
      The Sidhekin proves Sidhe did it!

        Ooops. Just needs a little positive lookbehind.

        perl -le 'for(@ARGV){s/\./,/;s/(?<=\d)(?=(\d\d\d)+(,|\Z))/./g;print}' +1234567.89 234567.89 1234567 234567 1.234.567,89 234.567,89 1.234.567 234.567

        update..

        Ok.. yours is shorter... mine is probably more efficient for not invoking $& at least :)

                        - Ant
                        - Some of my best work - (1 2 3)