I would like to take a number and format it as price (as a string). For example I want to take 250000 and display $250,000. How can I accomplish this using regex?
-
AFAIK, regex can't loop. Are you guaranteed an upper bound on the number? – beatgammit Mar 11 '13 at 15:09
-
Yes. Assume the number is bounded. – Addie Mar 11 '13 at 15:15
-
So, would $999,999 be an acceptable upper bound? – beatgammit Mar 11 '13 at 15:17
-
To put the commas you need to know the number of digits, this can't be achieved with regex only – ichigolas Mar 11 '13 at 15:18
-
Yes that would be OK. – Addie Mar 11 '13 at 15:20
4 Answers
For adding the commas you could give something like this a try:
/(\d)(?=(?:\d{3})+$)/
Then replace every match with \1,
.
As such:
"12345512312".gsub(/(\d)(?=(?:\d{3})+$)/,'\1,') => "12,345,512,312"
This would match any digit followed by an arbitrary number of 3 digit groups.
E.g. the first 2
in the above example is followed by 3 groups: 345
, 512
and 312
. The first 5
is followed by 2 groups: 512
and 312
, etc.
Not sure if you'll be able to add the $
in the same regex though.

- 1,559
- 11
- 15
-
Would you mind explaining how the `?:` works? It doesn't seem like it is necessary. – Addie Mar 13 '13 at 01:14
-
1Strictly speaking the `?:` is not necessary, all it does is make the grouping `\d{3}` a passive group (meaning no back-reference is created). We need to make this a group because we want to match 1 or more occurrences of `\d{3}`. We could've done `(\d{3})+`, but then `\2` would've back-referenced the matching numbers. In this case it would've made no difference, but it keeps it cleaner and makes the intent clearer when we use passive groups. – rvalvik Mar 13 '13 at 08:53
Try this one out (disclaimer- not a regex):
def prettify(n)
int, dec = n.to_s.split('.')
int = int.reverse.scan(/.{1,3}/).join(',').reverse
[int, dec].reject(&:empty?).join('.')
end
Probably a gem out there for this kind of thing though

- 31,780
- 20
- 84
- 118
Matching with regex it's a pain in the #@! in this case since regex engines begin matching from the beginning of the string, not the end (finding 3 digit patterns beginning at the end of the string and going backwards). I'd suggest either doing something like this:
format_int = ->(s) do
str = s.reverse.scan(/\d{1,3}/).join(',').reverse
"$#{str}"
end
format_int['2500600'] => "$2,500,600"
... using Kernel#sprintf
(this can be a little tricky) or, as you wanted:
I was wrong, it can be achieved with regex as shown here and here.
you should be using the number_to_currency helper
number_to_currency(1234567890.50) # => $1,234,567,890.50
number_to_currency(1234567890.506) # => $1,234,567,890.51
number_to_currency(1234567890.506, precision: 3) # => $1,234,567,890.506
number_to_currency(1234567890.506, locale: :fr) # => 1 234 567 890,51 €
number_to_currency("123a456") # => $123a456
number_to_currency("123a456", raise: true) # => InvalidNumberError
number_to_currency(-1234567890.50, negative_format: "(%u%n)")
# => ($1,234,567,890.50)
number_to_currency(1234567890.50, unit: "£", separator: ",", delimiter: "")
# => £1234567890,50
number_to_currency(1234567890.50, unit: "£", separator: ",", delimiter: "", format: "%n %u")
# => 1234567890,50 £
for more info look at http://api.rubyonrails.org/classes/ActionView/Helpers/NumberHelper.html

- 10,108
- 9
- 71
- 116