[c] C에서 1123456789에서 1,123,456,789로 숫자를 포맷하는 방법은 무엇입니까?
C 언어 형식으로 숫자를에서 1123456789
까지 어떻게 할 수 1,123,456,789
있습니까? 나는 사용해 printf("%'10d\n", 1123456789);
보았지만 작동하지 않습니다.
조언 해 주시겠습니까? 솔루션이 간단할수록 좋습니다.
답변
printf가 '
(POSIX 2008에서 요구하는대로) 플래그를 지원한다면 printf()
, 당신의 로케일을 적절하게 설정함으로써 가능할 것입니다. 예:
#include <stdio.h>
#include <locale.h>
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
2의 보수를 사용하는 경우이를 관리하려면 추가 코드가 필요합니다).
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
1,000 미만의 숫자 만 인쇄되고 반환됩니다. - 그렇지 않으면 1,000 미만의 숫자를 찾을 때까지 다음 레벨에서 재귀가 호출됩니다 (따라서 1,234,567은 1,234로 호출 된 다음 1).
- 그런 다음 그 숫자가 인쇄되고 재귀 트리로 돌아가서 쉼표와 다음 숫자를 인쇄합니다.
모든 수준 에서 음수를 검사 할 때 불필요한 처리를 수행하지만 더 간결한 버전도 있습니다 (제한된 수의 재귀 수준을 고려할 때 중요하지 않음). 이것은 테스트를위한 완전한 프로그램입니다.
#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
.
위의 모든 코드는 3 자리 그룹을 쉼표로 구분하기위한 것이지만 공백과 같은 다른 문자도 사용할 수 있습니다.
void printfspace2 (int n) {
if (n < 1000) {
printf ("%d", n);
return;
}
printfspace2 (n/1000);
printf (" %03d", n%1000);
}
void printfspace (int n) {
if (n < 0) {
printf ("-");
n = -n;
}
printfspace2 (n);
}
답변
다음은 매우 간단한 구현입니다. 이 함수는 오류 검사를 포함 하지 않으며 버퍼 크기는 호출자가 확인해야합니다. 음수에도 작동하지 않습니다. 이러한 개선 사항은 독자를위한 연습으로 남겨집니다.
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를 사용하여 항상이 작업을 수행합니다. 그렇습니다. ‘연산자는 비표준 일 수 있지만 단순함이 마음에 듭니다.
#include <stdio.h>
#include <locale.h>
int main()
{
int bignum=12345678;
setlocale(LC_ALL,"");
printf("Big number: %'d\n",bignum);
return 0;
}
다음의 출력을 제공합니다.
큰 숫자 : 12,345,678
거기에있는 ‘setlocale’호출을 기억해야합니다. 그렇지 않으면 아무것도 형식화하지 않습니다.
답변
로케일 인식 버전이 흥미로울 것입니다.
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <limits.h>
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 <stdio.h>
#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<elements(inputs); i++) {
setlocale(LC_ALL, "");
show(inputs[i]);
}
return 0;
}
#endif
이것은 버그가 있습니다 (하지만 상당히 사소하다고 생각하는 버그입니다). 2의 보수 하드웨어에서는 음수를 N = -N;
2의 보수에서 동등한 양수로 변환하려고 시도하기 때문에 가장 음수를 올바르게 변환 하지 않습니다. 더 큰 유형으로 승격하십시오. 이 문제를 해결하는 한 가지 방법은 해당하는 서명되지 않은 유형으로 숫자를 승격하는 것입니다 (그러나 다소 사소하지 않습니다).
답변
재귀 또는 문자열 처리없이 수학적 접근 방식 :
#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) ) ;
}
}
원칙적으로 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);
}