Как отформатировать номер от 1123456789 до 1 123 456 789 в C?

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

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

Если ваш printf поддерживает флаг ' , вы, вероятно, можете сделать это, установив свой язык соответствующим образом. Пример:

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

И построить и запустить:

 $ ./example 1,123,456,789 

Протестировано на Mac OS X и Linux (Ubuntu 10.10).

Вы можете сделать это рекурсивно следующим образом (остерегайтесь INT_MIN если вы используете два дополнения, для этого вам понадобится дополнительный код):

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

Совокупность:

  • Пользователь вызывает printfcomma с целым числом, специальный случай отрицательных чисел обрабатывается просто печатью «-» и делает число положительным (это бит, который не будет работать с INT_MIN ).
  • Когда вы вводите printfcomma2 , число, меньшее 1000, будет просто печататься и возвращаться.
  • В противном случае recursion будет вызываться на следующем уровне вверх (так что 1,234,567 будет вызываться с 1,234, затем 1), пока не будет найдено число менее 1000.
  • Затем это число будет напечатано, и мы вернемся к дереву рекурсии, печатаем запятую и следующее число, когда мы идем.

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

 #include  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 .

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

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

Egads! Я делаю это все время, используя gcc / g ++ и glibc на linux и да, «оператор может быть нестандартным, но мне нравится его простота.

 #include  #include  int main() { int bignum=12345678; setlocale(LC_ALL,""); printf("Big number: %'d\n",bignum); return 0; } 

Дает вывод:

Большое количество: 12 345 678

Просто нужно запомнить звонок «setlocale», иначе он ничего не форматирует.

Возможно, интересная версия, ориентированная на локаль, будет интересна.

 #include  #include  #include  #include  static int next_group(char const **grouping) { if ((*grouping)[1] == CHAR_MAX) return 0; if ((*grouping)[1] != '\0') ++*grouping; return **grouping; } size_t commafmt(char *buf, /* Buffer for formatted string */ int bufsize, /* Size of buffer */ long N) /* Number to convert */ { int i; int len = 1; int posn = 1; int sign = 1; char *ptr = buf + bufsize - 1; struct lconv *fmt_info = localeconv(); char const *tsep = fmt_info->thousands_sep; char const *group = fmt_info->grouping; char const *neg = fmt_info->negative_sign; size_t sep_len = strlen(tsep); size_t group_len = strlen(group); size_t neg_len = strlen(neg); int places = (int)*group; if (bufsize < 2) { ABORT: *buf = '\0'; return 0; } *ptr-- = '\0'; --bufsize; if (N < 0L) { sign = -1; N = -N; } for ( ; len <= bufsize; ++len, ++posn) { *ptr-- = (char)((N % 10L) + '0'); if (0L == (N /= 10L)) break; if (places && (0 == (posn % places))) { places = next_group(&group); for (int i=sep_len; i>0; i--) { *ptr-- = tsep[i-1]; if (++len >= bufsize) goto ABORT; } } if (len >= bufsize) goto ABORT; } if (sign < 0) { if (len >= bufsize) goto ABORT; for (int i=neg_len; i>0; i--) { *ptr-- = neg[i-1]; if (++len >= bufsize) goto ABORT; } } memmove(buf, ++ptr, len + 1); return (size_t)len; } #ifdef TEST #include  #define elements(x) (sizeof(x)/sizeof(x[0])) void show(long i) { char buffer[32]; commafmt(buffer, sizeof(buffer), i); printf("%s\n", buffer); commafmt(buffer, sizeof(buffer), -i); printf("%s\n", buffer); } int main() { long inputs[] = {1, 12, 123, 1234, 12345, 123456, 1234567, 12345678 }; for (int i=0; i 

У этого есть ошибка (но я считаю довольно незначительной). На аппаратном обеспечении двух компонентов он не будет правильно преобразовывать наиболее отрицательное число, поскольку он пытается преобразовать отрицательное число в его эквивалентное положительное число с N = -N; В дополнении два максимально отрицательное число не имеет соответствующего положительного числа, если вы не продвинете его к большему типу. Один из способов обойти это - продвигать номер соответствующего неподписанного типа (но это несколько нетривиально).

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

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

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

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

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

Основываясь на @Greg Hewgill, но учитывает отрицательные числа и возвращает размер строки.

 size_t str_format_int_grouped(char dst[16], int num) { char src[16]; char *p_src = src; char *p_dst = dst; const char separator = ','; int num_len, commas; num_len = sprintf(src, "%d", num); if (*p_src == '-') { *p_dst++ = *p_src++; num_len--; } for (commas = 2 - num_len % 3; *p_src; commas = (commas + 1) % 3) { *p_dst++ = *p_src++; if (commas == 1) { *p_dst++ = separator; } } *--p_dst = '\0'; return (size_t)(p_dst - dst); } 

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

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

Вот самая маленькая, размерная и быстродействующая реализация такого рода десятичных чисел:

 const char *formatNumber ( int value, char *endOfbuffer, bool plus) { int savedValue; int charCount; savedValue = value; if (unlikely (value < 0)) value = - value; *--endOfbuffer = 0; charCount = -1; do { if (unlikely (++charCount == 3)) { charCount = 0; *--endOfbuffer = ','; } *--endOfbuffer = (char) (value % 10 + '0'); } while ((value /= 10) != 0); if (unlikely (savedValue < 0)) *--endOfbuffer = '-'; else if (unlikely (plus)) *--endOfbuffer = '+'; return endOfbuffer; } 

Используйте следующее:

 char buffer[16]; fprintf (stderr, "test : %s.", formatNumber (1234567890, buffer + 16, true)); 

Вывод:

 test : +1,234,567,890. 

Некоторые преимущества:

  • Функция, принимающая конец буфера строки из-за обратного упорядоченного форматирования. Наконец, где нет необходимости в почитании сгенерированной строки (strrev).

  • Эта функция создает одну строку, которая может быть использована в любом альго после. Это не зависит и требует нескольких вызовов printf / sprintf, что ужасно медленно и всегда зависит от контекста.

  • Минимальное число операторов деления (/,%).

другое решение, сохраняя результат в массив int, максимальный размер, если 7 из-за длинного длинного int может обрабатывать число в диапазоне 9,223,372,036,854,775,807 до -9,223,372,036,854,775,807, отметив, note it is not an unsigned

нерекурсивная функция печати

 static void printNumber (int numbers[8], int loc, int negative) { if (negative) { printf("-"); } if (numbers[1]==-1)//one number { printf("%d ", numbers[0]); } else { printf("%d,", numbers[loc]); while(loc--) { if(loc==0) {// last number printf("%03d ", numbers[loc]); break; } else { // number in between printf("%03d,", numbers[loc]); } } } } в static void printNumber (int numbers[8], int loc, int negative) { if (negative) { printf("-"); } if (numbers[1]==-1)//one number { printf("%d ", numbers[0]); } else { printf("%d,", numbers[loc]); while(loc--) { if(loc==0) {// last number printf("%03d ", numbers[loc]); break; } else { // number in between printf("%03d,", numbers[loc]); } } } } 

вызов основной функции

 static void getNumWcommas (long long int n, int numbers[8]) { int i; int negative=0; if (n < 0) { negative = 1; n = -n; } for(i = 0; i<7; i++) { if (n < 1000) { numbers[i] = n; numbers[i+1] = -1; break; } numbers[i] = n%1000; n/=1000; } printNumber(numbers, i, negative);// non recursive print } 

результат тестирования

 -9223372036854775807: -9,223,372,036,854,775,807 -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 9223372036854775807 : 9,223,372,036,854,775,807 

в classе main ()

 int numberSeperated[8]; long long int number = 1234567890LL; getNumWcommas(number, numberSeperated ); 

если печать необходима, переместите int numberSeperated[8]; внутри функции getNumWcommas и называть ее таким образом getNumWcommas(number);

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

Результат будет выглядеть следующим образом:

Value: 0'000'012'345

Код:

 printf("Value: %llu'%03lu'%03lu'%03lu\n", (value / 1000 / 1000 / 1000), (value / 1000 / 1000) % 1000, (value / 1000) % 1000, value % 1000); 

Защитить format_commas с отрицательными номерами:

Поскольку VS <2015 не реализует snprintf, вам нужно сделать это

 #if defined(_WIN32) #define snprintf(buf,len, format,...) _snprintf_s(buf, len,len, format, __VA_ARGS__) #endif 

А потом

 char* format_commas(int n, char *out) { int c; char buf[100]; char *p; char* q = out; // Backup pointer for return... if (n < 0) { *out++ = '-'; n = abs(n); } snprintf(buf, 100, "%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; return q; } 

Пример использования:

 size_t currentSize = getCurrentRSS(); size_t peakSize = getPeakRSS(); printf("Current size: %d\n", currentSize); printf("Peak size: %d\n\n\n", peakSize); char* szcurrentSize = (char*)malloc(100 * sizeof(char)); char* szpeakSize = (char*)malloc(100 * sizeof(char)); printf("Current size (f): %s\n", format_commas((int)currentSize, szcurrentSize)); printf("Peak size (f): %s\n", format_commas((int)currentSize, szpeakSize)); free(szcurrentSize); free(szpeakSize); 

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

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

Измененная версия решения @paxdiablo, но с использованием WCHAR и wsprinf :

 static WCHAR buffer[10]; static int pos = 0; void printfcomma(const int &n) { if (n < 0) { wsprintf(buffer + pos, TEXT("-")); pos = lstrlen(buffer); printfcomma(-n); return; } if (n < 1000) { wsprintf(buffer + pos, TEXT("%d"), n); pos = lstrlen(buffer); return; } printfcomma(n / 1000); wsprintf(buffer + pos, TEXT(",%03d"), n % 1000); pos = lstrlen(buffer); } void my_sprintf(const int &n) { pos = 0; printfcomma(n); } 

Я новичок в программировании на С. Вот мой простой код.

 int main() { // 1223 => 1,223 int n; int a[10]; printf(" n: "); scanf_s("%d", &n); int i = 0; while (n > 0) { int temp = n % 1000; a[i] = temp; n /= 1000; i++; } for (int j = i - 1; j >= 0; j--) { if (j == 0) { printf("%d.", a[j]); } else printf("%d,",a[j]); } getch(); return 0; } 
 #include  void punt(long long n){ char s[28]; int i = 27; if(n<0){n=-n; putchar('-');} do{ s[i--] = n%10 + '0'; if(!(i%4) && n>9)s[i--]='.'; n /= 10; }while(n); puts(&s[++i]); } int main(){ punt(2134567890); punt(987); punt(9876); punt(-987); punt(-9876); punt(-654321); punt(0); punt(1000000000); punt(0x7FFFFFFFFFFFFFFF); punt(0x8000000000000001); // -max + 1 ... } в #include  void punt(long long n){ char s[28]; int i = 27; if(n<0){n=-n; putchar('-');} do{ s[i--] = n%10 + '0'; if(!(i%4) && n>9)s[i--]='.'; n /= 10; }while(n); puts(&s[++i]); } int main(){ punt(2134567890); punt(987); punt(9876); punt(-987); punt(-9876); punt(-654321); punt(0); punt(1000000000); punt(0x7FFFFFFFFFFFFFFF); punt(0x8000000000000001); // -max + 1 ... } 

Мое решение использует. вместо a, читателю это нужно изменить.

Можно сделать довольно легко …

 //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 
 void printfcomma ( long long unsigned int n) { char nstring[100]; int m; int ptr; int i,j; sprintf(nstring,"%llu",n); m=strlen(nstring); ptr=m%3; if (ptr) { for (i=0;i 
  // separate thousands int digit; int idx = 0; static char buffer[32]; char* p = &buffer[32]; *--p = '\0'; for (int i = fCounter; i != 0; i /= 10) { digit = i % 10; if ((p - buffer) % 4 == 0) *--p = ' '; *--p = digit + '0'; } 
Давайте будем гением компьютера.