How to format a number 1000 as “1 000”

2019-01-22 11:54发布

I need a way to format numbers. I stored some numbers in my DB table, e.g. 12500, and would like to print them in this format 12 500 (so there is a space every 3 digits). Is there an elegant way to do this?

12条回答
闹够了就滚
2楼-- · 2019-01-22 12:15

So, this is pretty crazy and hackish, but it gets the job done...

12500.to_s.split("").reverse.each_slice(3).map {|y| y.join("").reverse}.reverse.join(" ")
 => "12 500" 

.to_s: convert to string
.split(""): split into separate digits
.reverse: reverse order
.each_slice(3): peel of each three digits (working from back end due to reverse)
.map {|y| y.join("").reverse}: map into an array for each three digits - join back together with no delimiter and reverse order back to original
.reverse: reverse order of mapped array
.join(" "): join mapped array back together with space delimiter
查看更多
男人必须洒脱
3楼-- · 2019-01-22 12:16

I just stumbled on this thread while looking for a way to format a value as US currency. I took a slightly different approach to the regex solutions proposed:

amt = 1234567890.12
f_amt = format("$%.2f",amt)
i = f_amt.index(".")
while i > 4
  f_amt[i-3]=","+f_amt[i-3]
  i = f_amt.index(",")
end

f_amt
=> "$1,234,567,890.12"

This could be parameterized for formatting other currencies.

查看更多
你好瞎i
4楼-- · 2019-01-22 12:22

The official document suggests three different ways:

1) Using lookbehind and lookahead (Requires oniguruma)

12500.to_s.gsub(/(?<=\d)(?=(?:\d{3})+\z)/, ' ')
# => "12 500"

2) Using only lookahead. Identical to steenslag's answer.

3) Using neither lookahead nor lookbehind

s = 12500.to_s
nil while s.sub!(/(.*\d)(\d{3})/, '\1 \2')
s # => "12 500"
查看更多
劫难
5楼-- · 2019-01-22 12:25

Here's another method that is fairly clean and straightforward if you are dealing with integers:

number.to_s.reverse.scan(/\d{1,3}/).join(",").reverse

number            #=> 12345678
.to_s             #=> "12345678"
.reverse          #=> "87654321"
.scan(/\d{1,3}/)  #=> ["876","543","21"]
.join(",")        #=> "876,543,21"
.reverse          #=> "12,345,678"

Works great for integers. Of course, this particular example will separate the number by commas, but switching to spaces or any other separator is as simple as replacing the parameter in the join method.

查看更多
我想做一个坏孩纸
6楼-- · 2019-01-22 12:25

Another way:

12500.to_s.reverse().split(//).inject() {|x,i| (x.gsub(/ /,"").length % 3 == 0 ) ? x + " " + i : x + i}.reverse()

You can always Open the Fixnum class and add this for convenience:

module FormatNums
  def spaceify
    self.to_s.reverse().split(//).inject() {|x,i| (x.gsub(/ /,"").length % 3 == 0 ) ? x + " " + i : x + i}.reverse()
  end
end

class Fixnum
  include FormatNums
end

12500.spaceify # => "12 500"
查看更多
We Are One
7楼-- · 2019-01-22 12:27

All but one of the answers use n.to_s. @MrMorphe's does not, but he creates an array to be joined. Here's a way that uses neither Fixnum#to_s nor Array#join.

def separate(n,c=' ')
  m = n
  str = ''
  loop do
    m,r = m.divmod(1000)
    return str.insert(0,"#{r}") if m.zero?
    str.insert(0,"#{c}#{"%03d" % r}")
  end
end

separate(1)       #=>         "1"
separate(12)      #=>        "12"
separate(123)     #=>       "123"
separate(1234)    #=>     "1 234"
separate(12045)   #=>    "12 045"
separate(123456)  #=>   "123 456"
separate(1234000) #=> "1 234 000"

Hmmm. Is that column on the right tipping?

Another way that uses to_s but not join:

def separate(n, c=' ')
  str = n.to_s
  sz = str.size
  (3...sz).step(3) { |i| str.insert(sz-i, c) }
  str
end
查看更多
登录 后发表回答