2012-02-06 54 views
5

格式化數字時,我想在每三個字符處放置一個空格。根據該規範:格式化一個數字以便每隔三位分割一次

it "should format an amount" do 
    spaces_on(1202003).should == "1 202 003" 
    end 

,我想出了這樣一段代碼,沒有工作

def spaces_on amount 
    thousands = amount/1000 
    remainder = amount % 1000 
    if thousands == 0 
     "#{remainder}" 
    else 
     zero_padded_remainder = '%03.f' % remainder 
     "#{spaces_on thousands} #{zero_padded_remainder}" 
    end 
    end 

所以我的問題是,如果這是做到這一點的最好辦法。我懷疑可能存在一種正則表達式,但我不確定我會喜歡這種可讀性。 (在另一方面 - 在%03.f魔法不是很可讀要麼....)

回答

5
>> def spaces_on number 
>> number.to_s.gsub(/\D/, '').reverse.gsub(/.{3}/, '\0 ').reverse 
>> end 
=> nil 
>> spaces_on 12345678 
=> "12 345 678" 

也許有正則表達式不驚人的可讀的說法,但我個人認爲他們是簡單理解而不必考慮遞歸。

+0

+1你把正確的答案在我心裏! =) – maerics 2012-02-06 20:15:56

+0

不錯的一塊。我發現許多開發人員根本不知道正則表達式,這讓我避免了這種情況 - 但遞歸也是如此!採取的點。 – froderik 2012-02-06 20:17:12

+0

當然,這裏的魔術不是正則表達式 - 一旦你知道方法的目標,就很容易挑出'每3個字符添加一個空格'位。 「反向」/「反向」是唯一真正的心理跳躍。 – Gareth 2012-02-06 20:21:53

3

這是Rails嗎?

number_with_delimiter(@number, :delimiter => ' ') 

來自ActionView::Helpers::NumberHelper

如果你想與負數小數點工作的獨立版本,使用:

def spaces_on number 
    parts = number.to_s.split('.') 
    parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1 ") 
    parts.join(".") 
end 

在正則表達式的邏輯是這樣的:捕捉每一個僅由3組隨後位數字(沒有剩餘的數字),並輸出它的空間。

+0

你的'123.4567'失敗,產生''123.4 567「'。但是,+1提到Rails版本,其中可以查看源代碼。 (一旦你扔掉了i18n「絨毛」,在'.'上分割的核心,在整數半部分使用'gsub!',再次加入''加入''是很優雅的。) – Phrogz 2012-02-06 21:03:34

+0

好的。我更新了我的模仿幫手。現在應該在這種情況下工作。 – 2012-02-06 21:13:04

5

的加雷斯的解決方案的一小修改(一個更復雜的正則表達式,但沒有串倒車):

def spaces_on number 
    number.to_s.gsub(/\d(?=(...)+$)/, '\0 ') 
end 

它爲負數太(但浮動不工作)。

5

def spaces_on(number,sep=" ") 
    number.to_s.tap do |s| 
    :go while s.gsub!(/^([^.]*)(\d)(?=(\d{3})+)/, "\\1\\2#{sep}") 
    end 
end 

NUMBERS = [ 1, 12, 123, 1234, 12345, 123456, 1234567, 
      1.0, 1.2, 1.23, 1.234, 1.2345, 1.23456, 1.234567, 
      12.3, 12.34, 12.345, 12.3456, 
      123.4, 123.45, 123.456, 123.4567, 
      1234.5, 1234.5, 1234.56, 1234.567, 1234.5678 ] 

NUMBERS.each do |n| 
    puts "%10s: %s" % [ n, spaces_on(n).inspect ] 
    puts "%10s: %s" % [ -n, spaces_on(-n).inspect ] 
end 

產地:

  1: "1" 
     -1: "-1" 
     12: "12" 
     -12: "-12" 
     123: "123" 
     -123: "-123" 
     1234: "1 234" 
    -1234: "-1 234" 
    12345: "12 345" 
    -12345: "-12 345" 
    123456: "123 456" 
    -123456: "-123 456" 
    1234567: "1 234 567" 
    -1234567: "-1 234 567" 
     1.0: "1.0" 
     -1.0: "-1.0" 
     1.2: "1.2" 
     -1.2: "-1.2" 
     1.23: "1.23" 
    -1.23: "-1.23" 
    1.234: "1.234" 
    -1.234: "-1.234" 
    1.2345: "1.2345" 
    -1.2345: "-1.2345" 
    1.23456: "1.23456" 
    -1.23456: "-1.23456" 
    1.234567: "1.234567" 
-1.234567: "-1.234567" 
     12.3: "12.3" 
    -12.3: "-12.3" 
    12.34: "12.34" 
    -12.34: "-12.34" 
    12.345: "12.345" 
    -12.345: "-12.345" 
    12.3456: "12.3456" 
    -12.3456: "-12.3456" 
    123.4: "123.4" 
    -123.4: "-123.4" 
    123.45: "123.45" 
    -123.45: "-123.45" 
    123.456: "123.456" 
    -123.456: "-123.456" 
    123.4567: "123.4567" 
-123.4567: "-123.4567" 
    1234.5: "1 234.5" 
    -1234.5: "-1 234.5" 
    1234.5: "1 234.5" 
    -1234.5: "-1 234.5" 
    1234.56: "1 234.56" 
    -1234.56: "-1 234.56" 
    1234.567: "1 234.567" 
-1234.567: "-1 234.567" 
1234.5678: "1 234.5678" 
-1234.5678: "-1 234.5678" 
+0

耶 - 進入深度正則表達式空間! – froderik 2012-02-06 21:05:39

+0

在ActionView文檔中,你調用'sep'的東西叫做分隔符。分隔符用於分數和整數數字之間的字符。 (我對什麼是最好的沒有意見,但起初我感到困惑。)否則+1 – steenslag 2012-02-06 21:20:25

+0

哦,我的嘗試被稱爲'to_s_with_delim',在'Numeric'上定義,這就是爲什麼我注意到了。'spaces_on'不是一個很好的方法名稱恕我直言。但仍然+1 :) – steenslag 2012-02-06 21:24:36

相關問題