1

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?

5
  • AFAIK, regex can't loop. Are you guaranteed an upper bound on the number? Commented Mar 11, 2013 at 15:09
  • Yes. Assume the number is bounded. Commented Mar 11, 2013 at 15:15
  • So, would $999,999 be an acceptable upper bound? Commented 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 only Commented Mar 11, 2013 at 15:18
  • Yes that would be OK. Commented Mar 11, 2013 at 15:20

4 Answers 4

5

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Would you mind explaining how the ?: works? It doesn't seem like it is necessary.
Strictly 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.
2

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

Comments

2

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

This is a cleaner solution
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.