2010-09-12 3 views
0

J'ai trouvé cet extrait en ligne et le but est de préciser n'importe quel nombre incluant les nombres décimaux ... 99999999 => 99,999,999. Je peux voir qu'il utilise regex mais je suis confus par « 1.reverse $, 2 $ »Expliquer Ruby Commettre la méthode des grands nombres entiers

def commify(n) 
    n.to_s =~ /([^\.]*)(\..*)?/ 
    int, dec = $1.reverse, $2 ? $2 : "" 
    while int.gsub!(/(,|\.|^)(\d{3})(\d)/, '\1\2,\3') 
    end 
    int.reverse + dec 
end 

Quelqu'un peut-il expliquer ce qui se passe dans ce code?

Répondre

5

$1, $2, $3 ... sont l'héritage de Perl. Ce sont des variables capture group, c'est-à-dire qu'elles capturent les groupes à l'intérieur de l'expression régulière.

Un groupe nommé est indiqué entre parenthèses. Ainsi, le premier groupe de capture correspond à ([^\.]), qui est un caractère non point, et (\..*) correspond à un caractère de point \. et à tous les autres caractères qui le suivent. Notez que le deuxième groupe est optionnel, donc dans la ligne ci-dessous vous avez l'expression ternaire $2 ? $2 : "", qui est une façon cryptique d'obtenir soit la valeur de la capture d'une chaîne vide. Le int, dec = $1, $2_or_blank_string est un parallel assignment. Ruby prend en charge l'affectation de plusieurs variables à la fois, ce n'est pas différent que de faire int = $1.reversed puis dec = $2 Donc contient maintenant la partie entière (inversée) et dec la partie décimale du nombre. Nous sommes intéressés par le premier pour l'instant.

Le prochain while vide remplace une chaîne. La méthode gsub! remplace toutes les occurrences de l'expression régulière pour la valeur de l'argument seconf. Mais il renvoie nil si aucun changement n'est survenu, ce qui termine le while.

Les matches d'expression /(,|\.|^)(\d{3})(\d)/:

  1. (,|\.|^) une virgule, un point ou le début de la chaîne
  2. (\d{3}) Trois chiffres
  3. (\d) Un quatrième chiffre

remplace alors pour . Le \n dans une substitution de chaîne signifie le nième groupe de capture, tout comme les variables $n. Donc, il fait essentiellement: si j'ai quatre chiffres, il suffit d'ajouter une virgule après le troisième. Répéter jusqu'à ce qu'aucun groupe de quatre chiffres ne soit trouvé

Ensuite, il suffit d'inverser à nouveau la partie entière et d'ajouter la partie décimale.

5

n.to_s =~ /([^\.]*)(\..*)?/ prend le nombre comme une chaîne et stocke tout avant la virgule (ou simplement tout s'il n'y a pas de point décimal) dans $1 et tout ce qui suit et y compris dans $2.

int, dec = $1.reverse, $2 ? $2 : "" stocke l'inverse de $1 dans int et $2 ou "" si $2 est nil, en dec. En d'autres termes int contient maintenant la partie avant le point décimal inversé et dec contient la partie après le point (non inversé).

La ligne suivante insère une virgule toutes les trois positions dans int. Donc, en inversant int à nouveau, nous obtenons la partie intégrale originale du nombre avec des virgules insérées tous les trois endroits de la fin. Maintenant nous ajoutons dec à la fin et obtenons le nombre original avec des virgules aux bons endroits.

3

Une autre façon:

class Integer 
    def commify 
    self.to_s.gsub(/(\d)(?=(\d{3})+$)/,'\1,') 
    end 
end 

Ensuite, vous pouvez le faire 12345678.commify et obtenir la chaîne 12,345,678

Et voici celui qui traite les nombres à virgule flottante:

class Float 
    def commify 
    self.to_s.reverse.gsub(/(\d\d\d)(?=\d)(?!\d*\.)/,'\1,').reverse 
    end 
end 
Questions connexes