Как отформатировать число от 1123456789 до 1,123,456,789 в C?

Как может, я на языке C форматирую число от 1123456789 кому: 1,123,456,789? Я пытался использовать printf("%'10d\n", 1123456789); но это не работает.

Вы могли советовать чему-нибудь? Чем более простой решение, тем лучше.

73
задан Rich 1 February 2017 в 10:35
поделиться

6 ответов

Это довольно легко сделать ...

//Make sure output buffer is big enough and that input is a valid null terminated string
void pretty_number(const char* input, char * output)
{
    int iInputLen = strlen(input);
    int iOutputBufferPos = 0;
    for(int i = 0; i < iInputLen; i++)
    {
        if((iInputLen-i) % 3 == 0 && i != 0)
        {
            output[iOutputBufferPos++] = ',';
        }

        output[iOutputBufferPos++] = input[i];
    }

    output[iOutputBufferPos] = '\0';
}

Пример вызова:

char szBuffer[512];
pretty_number("1234567", szBuffer);
//strcmp(szBuffer, "1,234,567") == 0
-1
ответ дан 24 November 2019 в 12:18
поделиться

Другая итерационная функция

int p(int n) {
  if(n < 0) {
    printf("-");
    n = -n;
  }

  int a[sizeof(int) * CHAR_BIT / 3] = { 0 };
  int *pa = a;
  while(n > 0) {
    *++pa = n % 1000;
    n /= 1000;
  }
  printf("%d", *pa);
  while(pa > a + 1) {
    printf(",%03d", *--pa);
  }
}
1
ответ дан 24 November 2019 в 12:18
поделиться

Математический подход без рекурсии или обработки строк:

#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) ) ;
    }
}

В принципе аналогичен рекурсивному решению Пакса, но при предварительном расчете порядка величины рекурсия избегается (возможно, за счет значительных затрат).

Обратите внимание также, что фактический символ, используемый для разделения тысяч, зависит от локали.

Изменить : См. комментарии @ Chux ниже для улучшения.

3
ответ дан 24 November 2019 в 12:18
поделиться

Вот очень простая реализация. Эта функция не содержит проверки ошибок , размеры буфера должны быть проверены вызывающей стороной. Это также не работает для отрицательных чисел. Такие улучшения оставлены в качестве упражнения для читателя.

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;
}
11
ответ дан 24 November 2019 в 12:18
поделиться

Это будет полностью зависеть от того, в каком домене вы работаете. Для некоторых это будут номера телефонов и SSN, а для других - адреса электронной почты, IP-адреса, URL-адреса. Самое важное - знать, когда вам нужно регулярное выражение, а когда нет. Например, если вы пытаетесь проанализировать данные из файла XML или HTML, обычно лучше использовать библиотеку, специально разработанную для анализа этого содержимого, чем пытаться написать что-нибудь самостоятельно.

  • Затем это число будет напечатано, и мы вернемся к дереву рекурсии, напечатав запятую и следующее число по мере продвижения.

  • Существует также более сжатая версия, хотя она выполняет ненужную обработку при проверке отрицательного числа на на каждом уровне (не то чтобы это будет иметь значение, учитывая ограниченное количество уровней рекурсии). Это полная программа для тестирования:

    #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;
    }
    

    , а результат:

    -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
    

    Итерационное решение для тех, кто не доверяет рекурсии (хотя единственная проблема с рекурсией, как правило, связана с пространством стека, которое здесь не будет проблемой поскольку это будет только несколько уровней глубины даже для 64-битного целого числа):

    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);
        }
    }
    

    Оба они генерируют 2 147 483 647 для INT_MAX .

    печать запятой и следующего числа по мере продвижения.

    Существует также более сжатая версия, хотя она выполняет ненужную обработку при проверке отрицательных чисел на на каждом уровне (не то чтобы это имеет значение, учитывая ограниченное число уровней рекурсии). Это полная программа для тестирования:

    #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;
    }
    

    , а результат:

    -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
    

    Итерационное решение для тех, кто не доверяет рекурсии (хотя единственная проблема с рекурсией, как правило, связана с пространством стека, которое здесь не будет проблемой поскольку это будет только несколько уровней глубины даже для 64-битного целого числа):

    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);
        }
    }
    

    Оба они генерируют 2 147 483 647 для INT_MAX .

    печать запятой и следующего числа по мере продвижения.

    Существует также более сжатая версия, хотя она выполняет ненужную обработку при проверке отрицательных чисел на на каждом уровне (не то чтобы это имеет значение, учитывая ограниченное число уровней рекурсии). Это полная программа для тестирования:

    #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;
    }
    

    , а результат:

    -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
    

    Итерационное решение для тех, кто не доверяет рекурсии (хотя единственная проблема с рекурсией, как правило, связана с пространством стека, которое здесь не будет проблемой поскольку это будет только несколько уровней глубины даже для 64-битного целого числа):

    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);
        }
    }
    

    Оба они генерируют 2 147 483 647 для INT_MAX .


    Существует также более сжатая версия, хотя она выполняет ненужную обработку при проверке отрицательных чисел на на каждом уровне (не то чтобы это будет иметь значение, учитывая ограниченное количество уровней рекурсии). Это полная программа для тестирования:

    #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;
    }
    

    , а результат:

    -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
    

    Итеративное решение для тех, кто не доверяет рекурсии (хотя единственная проблема с рекурсией, как правило, связана с пространством стека, которое здесь не будет проблемой поскольку это будет только несколько уровней глубины даже для 64-битного целого числа):

    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);
        }
    }
    

    Оба они генерируют 2 147 483 647 для INT_MAX .


    Существует также более сжатая версия, хотя она выполняет ненужную обработку при проверке отрицательных чисел на на каждом уровне (не то чтобы это будет иметь значение, учитывая ограниченное количество уровней рекурсии). Это полная программа для тестирования:

    #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;
    }
    

    , а результат:

    -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
    

    Итеративное решение для тех, кто не доверяет рекурсии (хотя единственная проблема с рекурсией, как правило, связана с пространством стека, которое здесь не будет проблемой поскольку это будет только несколько уровней глубины даже для 64-битного целого числа):

    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);
        }
    }
    

    Оба они генерируют 2 147 483 647 для INT_MAX .

    42
    ответ дан 24 November 2019 в 12:18
    поделиться

    В языке C нет простого способа сделать это. Я бы просто изменил для этого функцию преобразования int в строку:

    void format_number(int n, char * out) {
        int i;
        int digit;
        int out_index = 0;
    
        for (i = n; i != 0; i /= 10) {
            digit = i % 10;
    
            if ((out_index + 1) % 4 == 0) {
                out[out_index++] = ',';
            }
            out[out_index++] = digit + '0';
        }
        out[out_index] = '\0';
    
        // then you reverse the out string as it was converted backwards (it's easier that way).
        // I'll let you figure that one out.
        strrev(out);
    }
    
    0
    ответ дан 24 November 2019 в 12:18
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: