83 votes

c++ : Formater un nombre avec des virgules ?

Je veux écrire une méthode qui prendra un entier et retournera un std::string de ce nombre entier formaté avec des virgules.

Exemple de déclaration :

std::string FormatWithCommas(long value);

Exemple d'utilisation :

std::string result = FormatWithCommas(7800);
std::string result2 = FormatWithCommas(5100100);
std::string result3 = FormatWithCommas(201234567890);
// result = "7,800"
// result2 = "5,100,100"
// result3 = "201,234,567,890"

Quelle est la façon C++ de formater un nombre en tant que string avec des virgules ?

(Le bonus serait de gérer double également).

0 votes

1 votes

1 votes

Ce qui est boiteux dans ces déclarations en double, c'est que j'ai cherché cette question avant en utilisant les termes de recherche les plus évidents et je n'ai trouvé aucune de ces questions. Mon titre est meilleur et plus pertinent, et la réponse acceptée à ma question est meilleure que les réponses à toutes ces questions.

63voto

Node Points 2259

Vous pouvez faire comme Jacob l'a suggéré, et imbue avec le "" locale - mais cela utilisera la locale par défaut du système, ce qui ne garantit pas l'obtention de la virgule. Si vous voulez forcer la virgule (indépendamment des paramètres régionaux par défaut du système), vous pouvez le faire en fournissant votre propre fichier numpunct facette. Par exemple :

#include <locale>
#include <iostream>
#include <iomanip>

class comma_numpunct : public std::numpunct<char>
{
  protected:
    virtual char do_thousands_sep() const
    {
        return ',';
    }

    virtual std::string do_grouping() const
    {
        return "\03";
    }
};

int main()
{
    // this creates a new locale based on the current application default
    // (which is either the one given on startup, but can be overriden with
    // std::locale::global) - then extends it with an extra facet that 
    // controls numeric output.
    std::locale comma_locale(std::locale(), new comma_numpunct());

    // tell cout to use our new locale.
    std::cout.imbue(comma_locale);

    std::cout << std::setprecision(2) << std::fixed << 1000000.1234;
}

1 votes

Je suis juste curieux de savoir si vous pouvez modifier votre exemple pour long, au lieu de float, puisque c'est ce que je cherchais (et c'est ce que la question demande).

1 votes

@FellowTraveler c'est la même chose, il suffit de faire std::cout << myLongValue; .

0 votes

Pourquoi cela fonctionne-t-il pour les longs même sans piping std::fixed ? (Je n'ai pas essayé les doubles).

60voto

Jacob Points 22306

Utilisez std::locale avec std::stringstream

#include <iomanip>
#include <locale>

template<class T>
std::string FormatWithCommas(T value)
{
    std::stringstream ss;
    ss.imbue(std::locale(""));
    ss << std::fixed << value;
    return ss.str();
}

Avis de non-responsabilité : La portabilité peut être un problème et vous devriez probablement regarder quelle locale est utilisée quand "" est passé

0 votes

4 votes

Cette fonction n'a pas mis de virgules pour moi. Quelle locale dois-je définir ? Quelle locale dois-je demander à mes utilisateurs de définir ? Échec.

1 votes

La réponse n'est pas complète sans un exemple d'utilisation d'une locale spécifique. Pour que cela fonctionne, il faut apprendre toute la machinerie locale.

41voto

user3400450 Points 108

Je considère que la réponse suivante est plus facile que les autres :

#include <iostream>
int main() {
   auto s = std::to_string(7654321);
   int n = s.length() - 3;
   while (n > 0) {
      s.insert(n, ",");
      n -= 3;
   }
   std::cout << (s == "7,654,321") << std::endl;
}   

Cela permettra d'insérer rapidement et correctement des virgules dans votre chaîne de chiffres.

0 votes

Cela ne fonctionnera pas avec des valeurs préfixées par des zéros comme 010100.

0 votes

@Homer6 Le problème des nombres négatifs pourrait être résolu par un ajustement mineur du code. Si le nombre est négatif, le critère de la boucle while devrait être insertPosition>1 ... pour -106, insertPosition commencerait à 1 et aucune virgule ne serait insérée.

0 votes

@Kapil les nombres préfixés par des zéros tels que 010100 fonctionneraient : vous obtiendriez insertPosition == 3 pour commencer, votre virgule irait entre les 3ème et 4ème chiffres et c'est tout. Pourriez-vous expliquer plus en détail comment une telle chaîne de chiffres pourrait échouer ?

2voto

troyane Points 2339

Si vous utilisez Qt, vous pouvez utiliser ce code :

const QLocale & cLocale = QLocale::c();
QString resultString = cLocale.toString(number);

N'oubliez pas non plus d'ajouter #include <QLocale> .

2voto

Tom Serink Points 29

C'est plutôt de la vieille école, je l'utilise dans les grandes boucles pour éviter d'instancier un autre tampon de chaîne.

void tocout(long a)
{
    long c = 1;

    if(a<0) {a*=-1;cout<<"-";}
    while((c*=1000)<a);
    while(c>1)
    {
       int t = (a%c)/(c/1000);
       cout << (((c>a)||(t>99))?"":((t>9)?"0":"00")) << t;
       cout << (((c/=1000)==1)?"":",");
    }
}

0 votes

J'aime ça (en dehors du manque d'espaces entre les opérateurs). Bien que les divisions par 1 000 soient probablement rapides sur les processeurs plus récents, vous pourriez allouer un tampon sur la pile et générer le nombre à l'envers et imprimer chaque caractère, et tous les 3, vous sortiriez également une virgule...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X