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– beatgammit2013-03-11 15:09:49 +00:00Commented Mar 11, 2013 at 15:09
-
Yes. Assume the number is bounded.Addie– Addie2013-03-11 15:15:26 +00:00Commented Mar 11, 2013 at 15:15
-
So, would $999,999 be an acceptable upper bound?beatgammit– beatgammit2013-03-11 15:17:06 +00:00Commented Mar 11, 2013 at 15:17
-
To put the commas you need to know the number of digits, this can't be achieved with regex onlyichigolas– ichigolas2013-03-11 15:18:09 +00:00Commented Mar 11, 2013 at 15:18
-
Yes that would be OK.Addie– Addie2013-03-11 15:20:18 +00:00Commented Mar 11, 2013 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.
2 Comments
?: works? It doesn't seem like it is necessary.?: 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.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.
1 Comment
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