Y a-t-il une astuce pour ajouter des virgules à de grands nombres?


201

Existe-t-il un moyen pour que les rails impriment un nombre avec des virgules?

Par exemple, si j'ai un numéro 54000000.34, je peux exécuter <% = number.function%>, qui afficherait "54,000,000.34"

Merci!

Réponses:


353

Vous voulez la number_with_delimiterméthode. Par exemple:

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

Vous pouvez également utiliser la number_with_precisionméthode pour vous assurer que le nombre est toujours affiché avec deux décimales de précision:

<%= number_with_precision(@number, :precision => 2, :delimiter => ',') %>

5
@Mo C'est une méthode d'aide à la vue. Vous devriez pouvoir l'utiliser à partir d'un module en l'incluant ActionView::Helpers::NumberHelperdans le module.
John Topley

9
Je crois que par défaut, le délimiteur est une virgule, vous n'avez donc pas besoin de passer cette option dans ce cas.
Deekor

3
Vous devez laisser le délimiteur désactivé afin que les paramètres régionaux actuels puissent décider quoi utiliser. Cela permet aux paramètres régionaux qui utilisent des périodes pour les délimiteurs d'être affichés correctement plutôt que de placer ce qu'ils considèrent comme un séparateur décimal entre des milliers. Voir la réponse coloradoblue ci-dessous.
Kyle Heironimus

1
Syntaxe Rails 4: <% = number_with_precision (@number, precision: 0, delimiter: ',')%>
Choylton B. Higginbottom

2
Attention: number_with_delimiterest trop complexe et très lent, avec d'énormes profondeurs de piles d'appels. Il i18npermet de formater tous les nombres connus de l'humanité et des civilisations extraterrestres (ou peut-être simplement de choisir l'un ,ou .pour les chiffres décimaux, même si vous le spécifiez comme argument). Il alloue des milliers d'objets (ses modèles de performances sont donc complexes et difficiles à profiler). Pensez à utiliser uniquement des expressions rationnelles si vous n'avez pas besoin de prendre en charge différentes façons de formater les nombres en fonction des paramètres régionaux.
kolen

133

Pour toute personne n'utilisant pas de rails:

number.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse

2
Agréable. Et votre réponse semble être minutieusement (seulement une fraction de seconde sur un million d'itérations) plus rapide que l'approche présentée ici :number.to_s.reverse.scan(/(?:\d*\.)?\d{1,3}-?/).join(',').reverse
user664833

pouvez-vous expliquer ce qui se passe ici? number.to_s.reverse.gsub (/ (\ d {3}) (? = \ d) /, '\\ 1,'). reverse
Stephen Nguyen

7
Bien sûr, il inverse la chaîne, puis ajoute une virgule après une séquence de 3 chiffres qui est également suivie d'un autre chiffre, puis l'inverse.
pguardiario

1
@renosis - Je vois ce que vous voulez dire maintenant, c'est pour le formatage de la devise. Donc 2 décimales, pas 7.
pguardiario

2
@pguardiario À quoi sert le \ dans le \\ 1? n'est pas \1suffisant? Merci.
butterywombat



24

Si vous souhaitez ajouter des virgules en dehors des vues et que vous ne souhaitez pas inclure certains modules, vous pouvez utiliser la méthode number_to_delimited (rails version> = 4.02). Par exemple:

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

19

Si vous le faites beaucoup mais aussi pour votre information car ce n'est pas impliqué par ce qui précède, Rails a des valeurs par défaut raisonnables pour la number_with_delimiterméthode.

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

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

Pas besoin de fournir la valeur du délimiteur si vous le faites de la manière la plus courante.


Cela a l'avantage supplémentaire d'utiliser les paramètres régionaux actuels. Ceci est vraiment important dans les applications internationales car certains paramètres régionaux utilisent une virgule pour le séparateur décimal et le point pour des milliers.
Kyle Heironimus

16

Une meilleure façon pour ceux qui n'utilisent pas de rails qui gèrent les décimales:

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

Si vous voulez un délimiteur différent, modifiez le dernier ',' dans l'expression régulière.

Pour les bonus, voici comment fonctionne l'expression régulière:

  • gsub remplace tout ce qui correspond à l'expression régulière avec le deuxième paramètre passé à gsub. Dans ce cas, c'est \\1. \\1devient une \1fois évalué qui correspond au premier groupe de capture dans l'expression régulière. Dans ce regex qui est(\d) .
  • (\d)(?=(\d\d\d)+)correspond à un chiffre suivi d'un ou plusieurs groupes de 3 chiffres. Le premier ensemble de parens est notre \1groupe de capture, le second le serait \2. Si nous devions en rester là, nous obtiendrions: 123456.gsub!(/(\d)(?=(\d\d\d)+)/, "\\1,") #=> 1,2,3,456c'est parce que 1234 correspondances, 2345 correspondances et 3456 correspondances, nous mettons donc une virgule après le 1, le 2 et le 3.
  • En ajoutant le (?! \ D), nous faisons correspondre tout ce qui précède qui ne précède pas un chiffre, cela (\d)(?=(\d\d\d)+(?!\d))signifie donc faire correspondre un chiffre suivi de 3 chiffres qui ne sont pas suivis d'un chiffre. La raison pour laquelle cela fonctionne est que gsub continuera de remplacer les éléments qui correspondent à la chaîne. Si nous devions seulement remplacer le premier match, alors pour un nombre comme 123456789, nous aurions 123456,789. Étant donné que 123456 789 correspond toujours à notre expression régulière, nous obtenons 123 456 789.

Voici où j'ai obtenu le code: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/number_helper.rb#L298-L300

Et voici où j'ai appris ce qui se passe dans cette expression régulière: http://www.tutorialspoint.com/ruby/ruby_regular_expressions.htm


fonctionne comme un charme, en particulier dans le modèle Liquid lang:{{ value | round | replace: "(\d)(?=(\d\d\d)+(?!\d))", "$1," | prepend: "$" }}
Kukunin

2

Une autre solution qui n'utilise pas Helpers: formatez avec 2 décimales, puis remplacez. par ,

puts(("%.2f" % 2.5666).gsub('.',','))
>> 2,57

1
Je crois que la question portait sur les virgules pour le regroupement des chiffres , et non sur la virgule comme séparateur décimal de partie / fraction de partie interne que votre réponse atteint. (comme ce lien wiki l'explique, en raison de la confusion de longue date, les normes Internetionnelles recommandent désormais les espaces uniquement pour le regroupement des chiffres)
Beni Cherniavsky-Paskin

1

Vous pouvez utiliser des méthodes de ActiveSupport

Par exemple:

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


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

C'était ma voie en rubis

Addition addition: Fondamentalement, il ajoute toutes les virgules entre les nombres et ne sélectionne que celles où l'index + 1% 6

Je pensais que les virgules jusqu'à 100 étaient bien, mais si vous voulez un nombre super long, faites simplement 100 un nombre plus élevé


0

nouvelle syntaxe

number_with_delimeter(@number, delimeter: ",")

Si vous souhaitez utiliser le délimiteur pour de l'argent, vous pouvez le faire

number_to_currency(@number)

cela ajoutera $aussi. Si vous utilisez moneygem, vous pouvez le faire

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

Cela mettra également $.

number_with_delimiter

argent rubis

number_to_currency


0

Les éléments suivants font l'affaire à la fois pour le délimiteur et la précision ( référence API ).

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

(ou simplement à partir de vues number_to_rounded, pas besoin du suffixe)

HTH


-1

pour les gens de javascript

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

:)

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.