95 votes

Comment formater un nombre de 1123456789 à 1 123 456 789 en C?

Comment puis-je en langage C formater un nombre de 1123456789 à 1,123,456,789 ? J'ai essayé d'utiliser printf("%'10d\n", 1123456789); mais cela ne fonctionne pas.

Pourriez-vous conseiller quelque chose? Plus la solution est simple, mieux c'est.

89voto

Carl Norum Points 114072

Si votre printf prend en charge le drapeau ' , vous pouvez probablement le faire simplement en définissant vos paramètres régionaux de manière appropriée. Exemple:

 #include <stdio.h>
#include <locale.h>

int main(void)
{
    setlocale(LC_NUMERIC, "");
    printf("%'d\n", 1123456789);
    return 0;
}
 

Et construire et exécuter:

 $ ./example 
1,123,456,789
 

Testé sur Mac OS X et Linux (Ubuntu 10.10).

48voto

paxdiablo Points 341644

Vous pouvez le faire de manière récursive comme suit (attention, INT_MIN si vous utilisez en complément à deux, vous aurez besoin de plus de code pour gérer ça):

void printfcomma2 (int n) {
    if (n < 1000) {
        printf ("%d", n);
        return;
    }
    printfcomma2 (n/1000);
    printf (",%03d", n%1000);
}

void printfcomma (int n) {
    if (n < 0) {
        printf ("-");
        n = -n;
    }
    printfcomma2 (n);
}

Un summmary:

  • L'utilisateur appelle printfcomma avec un nombre entier, le cas particulier des nombres négatifs est gérée par simplement l'impression de "-" et le nombre de résultats positifs (c'est ce qui ne fonctionne pas avec INT_MIN).
  • Lorsque vous entrez printfcomma2, un nombre inférieur à 1 000, il suffit d'imprimer et de retour.
  • Sinon, la récursivité sera appelé sur le niveau suivant (donc 1,234,567 sera appelée avec 1,234, puis 1) jusqu'à un nombre inférieur à 1 000 est trouvé.
  • Alors que le nombre sera imprimé et nous allons sauvegarder la récursivité de l'arbre, l'impression d'une virgule et du numéro suivant que nous allons.

Il y a aussi la version plus succincte mais il ne inutiles de traitement pour le contrôle pour les nombres négatifs à chaque niveau (non pas que cela n'aura d'importance étant donné le nombre limité de niveaux de récursivité). Celui-ci est un programme complet pour les tests:

#include <stdio.h>

void printfcomma (int n) {
    if (n < 0) {
        printf ("-");
        printfcomma (-n);
        return;
    }
    if (n < 1000) {
        printf ("%d", n);
        return;
    }
    printfcomma (n/1000);
    printf (",%03d", n%1000);
}

int main (void) {
    int x[] = {-1234567890, -123456, -12345, -1000, -999, -1,
               0, 1, 999, 1000, 12345, 123456, 1234567890};
    int *px = x;
    while (px != &(x[sizeof(x)/sizeof(*x)])) {
        printf ("%-15d: ", *px);
        printfcomma (*px);
        printf ("\n");
        px++;
    }
    return 0;
}

et la sortie est:

-1234567890    : -1,234,567,890
-123456        : -123,456
-12345         : -12,345
-1000          : -1,000
-999           : -999
-1             : -1
0              : 0
1              : 1
999            : 999
1000           : 1,000
12345          : 12,345
123456         : 123,456
1234567890     : 1,234,567,890

Une solution itérative pour ceux qui n'ont pas confiance en la récursivité (bien que le seul problème avec la récursivité a tendance à être un espace de pile qui ne sera pas un problème ici, car il ne prendra que quelques niveaux de profondeur, même pour un entier de 64 bits):

void printfcomma (int n) {
    int n2 = 0;
    int scale = 1;
    if (n < 0) {
        printf ("-");
        n = -n;
    }
    while (n >= 1000) {
        n2 = n2 + scale * (n % 1000);
        n /= 1000;
        scale *= 1000;
    }
    printf ("%d", n);
    while (scale != 1) {
        scale /= 1000;
        n = n2 / scale;
        n2 = n2  % scale;
        printf (",%03d", n);
    }
}

Ces deux générer 2,147,483,647 pour INT_MAX.

11voto

Greg Hewgill Points 356191

Voici une implémentation très simple. Cette fonction ne contient aucune vérification d'erreur, les tailles de mémoire tampon doivent être vérifiées par l'appelant. Cela ne fonctionne pas non plus pour les nombres négatifs. Ces améliorations sont laissées comme un exercice pour le lecteur.

 void format_commas(int n, char *out)
{
    int c;
    char buf[20];
    char *p;

    sprintf(buf, "%d", n);
    c = 2 - strlen(buf) % 3;
    for (p = buf; *p != 0; p++) {
       *out++ = *p;
       if (c == 1) {
           *out++ = ',';
       }
       c = (c + 1) % 3;
    }
    *--out = 0;
}
 

7voto

lornix Points 1328

Des œufs! Je le fais tout le temps, en utilisant gcc / g ++ et glibc sur linux et oui, l'opérateur 'est peut-être non standard, mais j'aime sa simplicité.

 #include <stdio.h>
#include <locale.h>

int main()
{
    int bignum=12345678;

    setlocale(LC_ALL,"");

    printf("Big number: %'d\n",bignum);

    return 0;
}
 

Donne la sortie de:

Grand nombre: 12 345 678

Souvenez-vous simplement de l'appel 'setlocale', sinon il ne formatera rien.

2voto

Clifford Points 29933

Sans récursion ni traitement des chaînes, une approche mathématique:

 #include <stdio.h>
#include <math.h>

void print_number( int n )
{
    int order_of_magnitude = (n == 0) ? 1 : (int)pow( 10, ((int)floor(log10(abs(n))) / 3) * 3 ) ;

    printf( "%d", n / order_of_magnitude ) ;

    for( n = abs( n ) % order_of_magnitude, order_of_magnitude /= 1000;
        order_of_magnitude > 0;
        n %= order_of_magnitude, order_of_magnitude /= 1000 )
    {
        printf( ",%03d", abs(n / order_of_magnitude) ) ;
    }
}
 

Semblable en principe à la solution récursive de Pax, mais en calculant à l'avance l'ordre de grandeur, on évite la récursivité (à un coût peut-être considérable).

Notez également que le caractère utilisé pour séparer des milliers dépend des paramètres régionaux.

Edit : Voir les commentaires de @ Chux ci-dessous pour des améliorations.

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