Existe um truque para adicionar vírgulas a grandes números?

201

Existe uma maneira de os trilhos imprimirem um número com vírgulas?

Por exemplo, se eu tiver um número 54000000.34, posso executar <% = number.function%>, que imprimiria "54.000.000.34"

obrigado!

Jess
fonte

Respostas:

353

Você quer o number_with_delimitermétodo Por exemplo:

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

Como alternativa, você pode usar o number_with_precisionmétodo para garantir que o número seja sempre exibido com duas casas decimais de precisão:

<%= number_with_precision(@number, :precision => 2, :delimiter => ',') %>
John Topley
fonte
5
@Mo É um método auxiliar de exibição. Você deve poder usá-lo a partir de um módulo, incluindo ActionView::Helpers::NumberHelperdentro do módulo.
John Topley
9
Por padrão, acredito que o delimitador é uma vírgula, portanto, você não precisaria passar nessa opção.
Deekor
3
Você deve deixar o delimitador desativado para que o código do idioma atual possa decidir o que usar. Isso permite que localidades que usam períodos para delimitadores sejam exibidas corretamente, em vez de colocar o que eles considerariam um ponto decimal entre milhares. Veja a resposta do coloradoblue abaixo.
Kyle Heironimus
1
Sintaxe do Rails 4: <% = number_with_precision (@number, precision: 0, delimiter: ',')%>
Choylton B. Higginbottom
2
Cuidado: number_with_delimiteré muito complexo e muito lento, com enormes profundidades de pilhas de chamadas. Ele costuma i18nser capaz de formatar qualquer número conhecido pela humanidade e por civilizações extraterrestres (ou talvez apenas escolher um ,ou .para dígitos decimais, mesmo se você o especificar como argumento). Ele aloca milhares de objetos (portanto, seus padrões de desempenho são complexos e difíceis de criar perfil). Considere usar apenas regexps se não precisar oferecer suporte a diferentes maneiras de formatar números, dependendo da localidade.
Kolen
133

Para quem não usa trilhos:

number.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
pguardiario
fonte
2
Agradável. E sua resposta parece ser minuciosa (apenas uma fração de segundo sobre um milhão de iterações) mais rápida que a abordagem apresentada aqui : number.to_s.reverse.scan(/(?:\d*\.)?\d{1,3}-?/).join(',').reverse
#
você pode explicar o que está acontecendo aqui? number.to_s.reverse.gsub (/ (\ d {3}) (= \ d) /, '\\ 1,'?) inverter.
Stephen Nguyen
7
Claro, ele reverte a sequência e adiciona uma vírgula após qualquer sequência de 3 dígitos que também é seguida por outro dígito, e depois a reverte.
pguardiario 22/02
1
@renosis - Entendo o que você quer dizer agora, isso é para formatação de moeda. Portanto, 2 casas decimais, não 7.
pguardiario
2
@pguardiario O que há de mais no \\ 1? não é \1suficiente? Obrigado.
butterywombat
31

A maneira direta de fazer isso, com ou sem Rails , é:

require 'active_support/core_ext/numeric/conversions'

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

Para obter mais opções, consulte Extensões principais do suporte ativo - numérico - formatação .

chocolateboy
fonte
1
E com essa inclusão, você também pode usar ActiveSupport::NumberHelper.number_to_delimited. Esta resposta merece muito mais votos.
Ulysse BN
30

Sim, use o NumberHelper . O método que você está procurando é number_with_delimiter .

 number_with_delimiter(98765432.98, :delimiter => ",", :separator => ".")
 # => 98,765,432.98
PatrikAkerstrand
fonte
24

Se você quiser adicionar vírgulas fora das visualizações e não incluir alguns módulos, poderá usar o método number_to_delimited (versão do rails> = 4.02). Por exemplo:

#inside anywhere
ActiveSupport::NumberHelper.number_to_delimited(1000000) # => "1,000,000"
Alexander Ryhlitsky
fonte
19

Se você está fazendo muito, mas também para o FYI, porque não está implícito no acima, o Rails possui padrões sensatos para o number_with_delimitermétodo.

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

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

Não é necessário fornecer o valor do delimitador se você estiver fazendo da maneira mais típica.

coloradoblue
fonte
Isso tem o benefício adicional de usar o código do idioma atual. Isso é realmente importante em aplicativos internacionais, pois alguns códigos de idioma usam vírgula para decimal e período para separador de milhares.
Kyle Heironimus
16

Uma maneira melhor para quem não usa trilhos que lida com decimais:

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

Se você quiser um delimitador diferente, altere o último ',' na regex.

Para bônus, é assim que a regex está funcionando:

  • O gsub substitui tudo o que corresponde à regex pelo segundo parâmetro passado para o gsub. Nesse caso, é isso \\1. \\1torna-se \1quando avaliado, que corresponde ao primeiro grupo de captura na regex. Nesse regex que é(\d) .
  • (\d)(?=(\d\d\d)+)está correspondendo a um dígito seguido por 1 ou mais grupos de 3 dígitos. O primeiro conjunto de parênteses é o nosso \1grupo de captura, o segundo seria \2. Se fôssemos deixar assim, teríamos: 123456.gsub!(/(\d)(?=(\d\d\d)+)/, "\\1,") #=> 1,2,3,456 isso ocorre porque 1234 correspondências, 2345 correspondências e 3456 correspondências, então colocamos uma vírgula após 1, 2 e 3.
  • Ao adicionar o (?! \ D), estamos correspondendo a qualquer coisa que venha antes que não preceda um dígito, portanto, (\d)(?=(\d\d\d)+(?!\d))significa igualar um dígito seguido por três dígitos que não são seguidos por um dígito. A razão pela qual isso funciona é que o gsub continuará substituindo coisas que correspondem à string. Se substituíssemos a primeira partida, para um número como 123456789, teríamos 123456.789. Como 123456.789 ainda corresponde ao nosso regex, obtemos 123.456.789.

Aqui é onde eu obtive o código: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/number_helper.rb#L298-L300

E aqui é onde eu aprendi sobre o que está acontecendo nesse regex: http://www.tutorialspoint.com/ruby/ruby_regular_expressions.htm

fxfilmxf
fonte
funciona como um encanto, especialmente em Liquid template lang:{{ value | round | replace: "(\d)(?=(\d\d\d)+(?!\d))", "$1," | prepend: "$" }}
Kukunin
2

Outra solução que não usa Helpers: formate com 2 casas decimais e substitua. de ,

puts(("%.2f" % 2.5666).gsub('.',','))
>> 2,57
Nino van Hooff
fonte
1
Acredito que a pergunta fosse sobre vírgulas para agrupamento de dígitos , e não vírgula como separador decimal de parte intergral / parte de fração que sua resposta alcança. (como que apontam wiki explica, devido à confusão de longa data, normas Internetional agora recomendam espaços única para dígito agrupamento)
Beni Cherniavsky-Paskin
1

Você pode usar métodos de ActiveSupport

Por exemplo:

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

Le Duc Duy
fonte
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

Este foi o meu caminho em rubi

Edição adicional: basicamente adiciona todas as vírgulas entre os números e seleciona apenas aquelas em que o índice + 1% 6

Achei que as vírgulas até 100 eram boas, mas se você quiser um número super longo, basta fazer 100 um número maior

Justin Cox
fonte
0

nova sintaxe

number_with_delimeter(@number, delimeter: ",")

Se você deseja delimeter por dinheiro, pode fazer

number_to_currency(@number)

isso irá adicionar $também. Se você estiver usando moneygem, então você pode fazer

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

Isso também colocará $ .

number_with_delimiter

dinheiro rubi

number_to_currency

gsumk
fonte
0

A seguir, faça o truque para delimitador e precisão ( ref da API ).

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

(ou apenas de visualizações number_to_rounded, não é necessário o sufixo)

HTH

Hertzel Guinness
fonte
-1

para pessoas javascript

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

:)

aqm
fonte