Currency formatting with regexp

Hi, all, this is my first post to Ruby-talk, so please be kind-- if that's not your natural disposition.

I'm looking to work up some code that turns floats into string-based currency values.

I've got an implementation working that's pretty ungodly. It looks a lot like I would program it in Java. Naturally, once I finished, I found some Perl suggestion that looks like this:

sub commify {
     my $text = reverse $_[0];
     $text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
     return scalar reverse $text;
}

I am a regexp noob. I experimented with using gsub and this regular expression, but I can't seem to get anywhere. The closest I've come replaces the first comma but then eliminates the rest of the number.

Can someone help me figure out what's going on-- or point me to where this is already available in Ruby? (Pickaxe II references neither money nor currency, and I don't really want to install extensions just for this functionality.)

Thanks so much,

Jim

Here's a direct Ruby translation:

def commify( number )
  text = number.to_s.reverse
  text.gsub!(/(\d\d\d)(?=\d)(?!\d*\.)/, '\1,')
  text.reverse
end

Hope that helps.

James Edward Gray II

···

On Feb 11, 2005, at 12:04 PM, Jim Van Fleet wrote:

sub commify {
    my $text = reverse $_[0];
    $text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
    return scalar reverse $text;
}

Might I suggest looking at Gavin Sinclair's "extensions" package? This
has some code that I wrote and released under an MIT-style licence to
format numbers with commas and has a *lot* of different formatting
capabilities.

-austin

···

On Sat, 12 Feb 2005 03:04:35 +0900, Jim Van Fleet <jim@jimvanfleet.com> wrote:

I'm looking to work up some code that turns floats into string-based
currency values.

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

James Edward Gray II wrote:

···

On Feb 11, 2005, at 12:04 PM, Jim Van Fleet wrote:

Here's a direct Ruby translation:

def commify( number )
    text = number.to_s.reverse
    text.gsub!(/(\d\d\d)(?=\d)(?!\d*\.)/, '\1,')
    text.reverse
end

Hope that helps.

It sure did, and cut my LOC count in half.

What does \1 signify, exactly? Is this the active matched section of the source string at the time?

Cheers,

Jim

golf?

def commify(num)
  num.to_s.reverse.scan(/..?.?/).join(",").reverse
end

... sorry, couldn't resist. Weak character.

cheers,
Mark

···

On Sat, 12 Feb 2005 03:25:20 +0900, James Edward Gray II <james@grayproductions.net> wrote:

On Feb 11, 2005, at 12:04 PM, Jim Van Fleet wrote:

> sub commify {
> my $text = reverse $_[0];
> $text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
> return scalar reverse $text;
> }

Here's a direct Ruby translation:

def commify( number )
        text = number.to_s.reverse
        text.gsub!(/(\d\d\d)(?=\d)(?!\d*\.)/, '\1,')
        text.reverse
end

It sure did, and cut my LOC count in half.

Good news.

What does \1 signify, exactly? Is this the active matched section of the source string at the time?

In a replacement string, \N is equivalent to Perl's $N variables. Outside a replacement string, you can $N variables directly. You can also use them in the block form of gsub().

Hope that clears it up.

James Edward Gray II

···

On Feb 11, 2005, at 1:46 PM, Jim Van Fleet wrote:

Mark Hubbart <discordantus@gmail.com> writes:

Here's a direct Ruby translation:

def commify( number )
        text = number.to_s.reverse
        text.gsub!(/(\d\d\d)(?=\d)(?!\d*\.)/, '\1,')
        text.reverse
end

golf?

def commify(num)
  num.to_s.reverse.scan(/..?.?/).join(",").reverse
end

... sorry, couldn't resist. Weak character.

IMHO, that's even easier to read...

···

cheers,
Mark

--
Christian Neukirchen <chneukirchen@gmail.com> http://chneukirchen.org

[snip]

golf?

def commify(num)
  num.to_s.reverse.scan(/..?.?/).join(",").reverse
end

That one doesn't do well with floats, which was what the poster
was dealing with.

As an aside, the commify routine from the Perl FAQ (shown earlier)
was actually designed as a means of commifying multiple numbers
in a string in a single pass:

  str = "123456789.987654321 and $1500.00 and 3.14159"
  p str.reverse.gsub(/(\d\d\d)(?=\d)(?!\d*\.)/,'\1,').reverse

So if, for example, you were pulling numbers from a data source
and creating an output string of a series of LaTeX tables, you
could build the entire string first with the raw numbers and
commify it all at once after the fact -- much more efficient than
commifying each number as you build the string. (this was, in
fact, the use-case that led to this particular solution).

regards,
andrew

···

On Sat, 12 Feb 2005 09:32:49 +0900, Mark Hubbart <discordantus@gmail.com> wrote:

--
Andrew L. Johnson http://www.siaris.net/
      In theory, there's no difference between
      theory and practice, but in practice there is!

Andrew Johnson wrote:

···

On Sat, 12 Feb 2005 09:32:49 +0900, Mark Hubbart <discordantus@gmail.com> > wrote:
[snip]

> golf?
>
> def commify(num)
> num.to_s.reverse.scan(/..?.?/).join(",").reverse
> end

That one doesn't do well with floats, which was what the poster
was dealing with.

I think this works properly:

* def commify( n )
* n.to_s.reverse.gsub(/(\d{3})(?=\d+-?$)/,'\1,').reverse
* end