Есть ли хитрость с добавлением запятых к большим числам?

201

Есть ли способ, чтобы рельсы распечатывали число с запятыми в нем?

Например, если у меня есть номер 54000000.34, я могу запустить <% = number.function%>, которая выведет «54,000,000.34»

Спасибо!

Джесс
источник

Ответы:

353

Вы хотите number_with_delimiterметод. Например:

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

Кроме того, вы можете использовать number_with_precisionметод, чтобы гарантировать, что число всегда отображается с двумя десятичными разрядами точности:

<%= number_with_precision(@number, :precision => 2, :delimiter => ',') %>
Джон Топли
источник
5
@Mo Это вспомогательный метод просмотра. Вы должны иметь возможность использовать его из модуля, в том числе ActionView::Helpers::NumberHelperвнутри модуля.
Джон Топли
9
Я считаю, что по умолчанию разделитель - запятая, поэтому вам не нужно указывать эту опцию в этом случае.
Декор
3
Вы должны оставить разделитель выключенным, чтобы текущая локаль могла решить, что использовать. Это позволяет языкам, которые используют периоды для разделителей, отображаться правильно, а не помещать то, что они считают десятичной точкой между тысячами. Смотрите coloradoblue ответ ниже.
Кайл Хейронимус
1
Синтаксис Rails 4: <% = number_with_precision (@number, точность: 0, разделитель: ',')%>
Чойлтон Б. Хиггинботтом
2
Осторожно: number_with_delimiterслишком сложный и очень медленный, с огромной глубиной стеков вызовов. Он используется i18nдля того, чтобы иметь возможность форматировать любые числа, известные человечеству и внеземным цивилизациям (или, может быть, просто выбрать один ,или .для десятичных цифр, даже если вы укажете его в качестве аргумента). Он распределяет тысячи объектов (поэтому его шаблоны производительности сложны и трудно профилируемы). Попробуйте использовать регулярные выражения, если вам не нужно поддерживать разные способы форматирования чисел в зависимости от локали.
Колен
133

Для тех, кто не использует рельсы:

number.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
pguardiario
источник
2
Ницца. И ваш ответ кажется на минутку (всего лишь доли секунды на миллион итераций) быстрее, чем подход, представленный здесь :number.to_s.reverse.scan(/(?:\d*\.)?\d{1,3}-?/).join(',').reverse
user664833
Вы можете объяснить, что здесь происходит? number.to_s.reverse.gsub (/ (\ d {3}) (? = \ d) /, '\\ 1,'). реверс
Стивен Нгуен
7
Конечно, он переворачивает строку, затем добавляет запятую после любой последовательности из 3 цифр, за которой следует еще одна цифра, а затем переворачивает ее обратно.
pguardiario
1
@renosis - теперь я понимаю, что вы имеете в виду, это для форматирования валюты. Итак, 2 десятичных
знака
2
@pguardiario Что дополнительно \ для в \\ 1? не \1достаточно? Спасибо.
butterywombat
31

Прямой способ сделать это с Rails или без него:

require 'active_support/core_ext/numeric/conversions'

12345.to_s(:delimited)      # => "12,345"
12345.6789.to_s(:delimited) # => "12,345.6789"

Дополнительные параметры см. В разделе Расширения активной поддержки - Числовые - Форматирование .

chocolateboy
источник
1
И с этим включением вы можете использовать ActiveSupport::NumberHelper.number_to_delimitedтакже. Этот ответ заслуживает гораздо больше голосов.
Ulysse BN
30

Да, используйте NumberHelper . Метод, который вы ищете, это number_with_delimiter .

 number_with_delimiter(98765432.98, :delimiter => ",", :separator => ".")
 # => 98,765,432.98
PatrikAkerstrand
источник
24

Если вы хотите добавить запятые вне представлений и не хотите включать некоторые модули, вы можете использовать метод number_to_delimited (rails version> = 4.02). Например:

#inside anywhere
ActiveSupport::NumberHelper.number_to_delimited(1000000) # => "1,000,000"
Александр Рыхлицкий
источник
19

Если вы делаете это много, но также и к сведению, потому что это не подразумевается выше, у Rails есть разумные значения по умолчанию для number_with_delimiterметода.

#inside controller or view
number_with_delimiter(2444323.4)
#=> 2,444,323.30

#inside console
helper.number_with_delimiter(233423)
#=> 233,423

Не нужно указывать значение разделителя, если вы делаете это наиболее типичным способом.

coloradoblue
источник
Это имеет дополнительное преимущество использования текущей локали. Это действительно важно в международных приложениях, так как некоторые локали используют запятую для десятичного разделителя и точку для разделителя тысяч.
Кайл Хейронимус
16

Лучший способ для тех, кто не использует рельсы, которые обрабатывают десятичные дроби:

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

Если вы хотите использовать другой разделитель, измените последний символ ',' в регулярном выражении.

Для бонуса, это то, как работает регулярное выражение:

  • gsub заменяет все, что соответствует регулярному выражению, вторым параметром, передаваемым в gsub. В этом случае это так \\1. \\1становится \1при оценке, которая соответствует первой группе захвата в регулярном выражении. В этом регулярном выражении это (\d).
  • (\d)(?=(\d\d\d)+)соответствует цифре, за которой следуют 1 или более групп из 3 цифр. Первый набор паренов - это наша \1группа захвата, второй будет \2. Если бы мы просто оставили это, мы получили бы: 123456.gsub!(/(\d)(?=(\d\d\d)+)/, "\\1,") #=> 1,2,3,456Это потому, что 1234 совпадения, 2345 совпадений и 3456 совпадений, поэтому мы ставим запятую после 1, 2 и 3.
  • Добавляя (?! \ D), мы сопоставляем все, что находится до того, что не предшествует цифре, поэтому (\d)(?=(\d\d\d)+(?!\d))означает совпадение с цифрой, за которой следуют 3 цифры, за которыми не следует цифра. Причина, по которой это работает, заключается в том, что gsub будет продолжать заменять вещи, соответствующие строке. Если бы мы собирались заменить только первый матч, то для числа, такого как 123456789, мы получили бы 123456,789. Поскольку 123456,789 все еще соответствует нашему регулярному выражению, мы получаем 123,456,789.

Вот где я получил код: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/number_helper.rb#L298-L300

И вот где я узнал о том, что происходит в этом регулярном выражении: http://www.tutorialspoint.com/ruby/ruby_regular_expressions.htm

fxfilmxf
источник
работает как шарм, особенно в Жидком шаблоне lang:{{ value | round | replace: "(\d)(?=(\d\d\d)+(?!\d))", "$1," | prepend: "$" }}
Кукунин
2

Другое решение, которое не использует хелперы: отформатируйте с двумя десятичными знаками, а затем замените. по ,

puts(("%.2f" % 2.5666).gsub('.',','))
>> 2,57
Нино ван Хофф
источник
1
Я полагаю, что вопрос был о запятых для группировки цифр , а не о запятой как о десятичном разделителе части / дроби, которую достигает ваш ответ. (как объясняет эта вики-ссылка, из-за давней путаницы международные стандарты теперь рекомендуют пробелы только для группировки цифр)
Бени Чернявский-Паскин
1

Вы можете использовать методы из ActiveSupport

Например:

ActiveSupport::NumberHelper::number_to_currency(10000.1234,{precision: 2,unit: ''})

Le Duc Duy
источник
1
  def add_commas(numstring)
    correct_idxs = (1..100).to_a.select{|n| n % 6 == 0}.map{|n| n - 1}
     numstring.reverse.chars.join(",").chars.select.with_index{|x, i| i.even? || correct_idxs.include?(i)}.join.reverse
  end

Это был мой путь в рубине

Редактирование дополнения: по существу, оно добавляет все запятые между числами и выбирает только те, где индекс + 1% 6

Я полагал, что запятые до 100 - это хорошо, но если вы хотите получить супер длинное число, просто сделайте 100 большим числом

Джастин Кокс
источник
0

новый синтаксис

number_with_delimeter(@number, delimeter: ",")

Если вы хотите, чтобы пользователь delimeter за деньги, то вы можете сделать

number_to_currency(@number)

это тоже добавит $. Если вы используете moneyдрагоценный камень, то вы можете сделать

Money.new(@number,"USD").format

Это тоже будет ставить $.

number_with_delimiter

рубиновые деньги

number_to_currency

gsumk
источник
0

Следующее делает трюк как для разделителя, так и для точности ( API ref ).

ActiveSupport::NumberHelper.number_to_rounded(1234.532, delimiter: ',', precision: 1) 

(или просто из представлений number_to_rounded, суффикс не нужен)

НТН

Герцель Гиннесс
источник
-1

для javascript

function numberWithDelimiter(value) {
    return (value+"").split("").reverse().join("").replace(/(\d{3})(?=\d)/g, '$1,').split("").reverse().join("")
}

:)

АКМ
источник