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

The Mastering Regular Expressions book givs this example to comma-fy an integer. s/(?<=\d)(?=(\d\d\d)+(?!\d))/,/g This works great for integers but Ive been trying to use a regex with positive and negative lookaheads and behinds to do the same thing with floating point numbers. Actually, it doesn't HAVE to use those constructs to add the commas, I just thought that would be the most efficent way. What is the best way to do it? I can certainly come up with some inefficent ones by not using (+/-)look(aheads/behinds). Thanks monks!
while (<DATA>) { $_ =~ s/ #substitute (?<=\d) # find position having 1 number preceeding it (?=(\d\d\d)+(?!\d)) # ant the position have 1 or more groups +of three numbers following it with a non-number at the end /,/ # put a comma at this position g; # do this substitution golbally print "$_"; } __DATA__ 123 1234 12345 123446 1234567 1234567.1234

Replies are listed 'Best First'.
Re: Comma-fy floats with (+/-)look(aheads/behinds)
by tachyon (Chancellor) on Sep 22, 2003 at 01:55 UTC

    This is what we use. It is based on an RE devised by merlyn with a patch to fix issues with arbitrarily long decimal components ie stop it commifying after the decimal point. It expects to be fed numbers rather than arbitrary strings containing numbers. To use the basic function on arbirary strings you first need to extract the numbers and process them sequentially which you can do with a /ge RE.

    print add_commas( '+1234567.123456789010'), $/; print add_commas_arb_string( 'Hello +1234567.123456 Hello -1234567.123 +456' ); sub add_commas { my ( $number ) = @_; return undef unless $number; ( $number, my $dec ) = $number =~ m!([+-]?\d+)\.?(\d*)!; return undef unless $number; $number =~ s/(\d)(?=(\d{3})+(\D|$))/$1,/g if length($number) > 3; return $dec ? "$number.$dec" : $number; } sub add_commas_arb_string { my ( $string ) = @_; $string =~ s/([+-]?\d(?:\d*\.\d+|\d*))/add_commas($1)/ge; return $string; } __DATA__ +1,234,567.123456789010 Hello +1,234,567.123456 Hello -1,234,567.123456

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Comma-fy floats with (+/-)look(aheads/behinds)
by Roger (Parson) on Sep 22, 2003 at 04:56 UTC
    You could do just this...
    while (<DATA>) { /\./ ? s/(?<=\d)(?=(\d{3})+(?:\.))/,/g : s/(?<=\d)(?=(\d{3})+(?!\d))/,/g; print "$_"; } __DATA__ 123 1234 12345 123446 1234567 +12345678.12 -123456789.12345678
    Which will give the following result:
    123 1,234 12,345 123,446 1,234,567 +12,345,678.12 -123,456,789.12345678
    Which is exactly what you wanted.
      Thanks Roger. This was the answer I was looking for. I was trying (\.|(?!\d)) and I knew why it wasn't working. I couldn't think of a solution that only used look(aheads|behinds).

      All the answers were great. Thanks again.

Re: Comma-fy floats with (+/-)look(aheads/behinds)
by Abigail-II (Bishop) on Sep 22, 2003 at 11:04 UTC
    It isn't clear to me how you want to commify floats. How should 1234567.1234 be commified? As 1,234,567.1234, or as 1,234,567.123,4? In the former case, you're just commifying the integer part of the float, so you could use the example from the FAQ. In the latter case, commify the integer part as in the FAQ, and the fractional part as: s/(\d{3})(?=\d)/$1,/.

    Abigail

Re: Comma-fy floats with (+/-)look(aheads/behinds)
by Anonymous Monk on Sep 22, 2003 at 13:04 UTC
    I learned something from every reply. This is a really great site. Thanks everyone.