问题
I wish to output large numbers with thousand-separators (commas or spaces) — basically the same as in How to display numeric in 3 digit grouping but using printf
in C (GNU, 99).
If printf does not support digit grouping natively, how can I achieve this with something like printf("%s", group_digits(number))
?
It must support negative integers and preferably floats, too.
回答1:
If you can use POSIX printf, try
#include <locale.h>
setlocale(LC_ALL, ""); /* use user selected locale */
printf("%'d", 1000000);
回答2:
Here is a compact way of doing it:
// format 1234567.89 -> 1 234 567.89
extern char *strmoney(double value){
static char result[64];
char *result_p = result;
char separator = ' ';
size_t tail;
snprintf(result, sizeof(result), "%.2f", value);
while(*result_p != 0 && *result_p != '.')
result_p++;
tail = result + sizeof(result) - result_p;
while(result_p - result > 3){
result_p -= 3;
memmove(result_p + 1, result_p, tail);
*result_p = separator;
tail += 4;
}
return result;
}
For example, a call to strmoney(1234567891.4568)
returns the string "1 234 567 891.46"
. You can easily replace the space with another separator (such as a comma) by changing the separator
variable at the top of the function.
回答3:
A secure way to format thousand separators, with support for negative numbers:
Because VS < 2015 doesn't implement snprintf, you need to do this
#if defined(_WIN32)
#define snprintf(buf,len, format,...) _snprintf_s(buf, len,len, format, __VA_ARGS__)
#endif
And then
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;
}
Example usage:
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);
回答4:
My own version for unsigned int64:
char* toString_DigitGrouping( unsigned __int64 val )
{
static char result[ 128 ];
_snprintf(result, sizeof(result), "%lld", val);
size_t i = strlen(result) - 1;
size_t i2 = i + (i / 3);
int c = 0;
result[i2 + 1] = 0;
for( ; i != 0; i-- )
{
result[i2--] = result[i];
c++;
if( c % 3 == 0 )
result[i2--] = '\'';
} //for
return result;
} //toString_DigitGrouping
回答5:
#include <stdio.h>
int main() {
char str[50];
int len = 0;
scanf("%48[^\n]%n", str, &len);
int start = len % 3;
for(int i = 0; i < len; i++) {
if(i == start && i != 0) {
printf(" ");
} else if((i - start) % 3 == 0 && i != 0) {
printf(" ");
}
printf("%c", str[i]);
}
return 0;
}
回答6:
#include <stdio.h>
void punt(int 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(){
int a;
scanf("%d",&a);
punt(a);
}
回答7:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char *commify(char *numstr){
char *wk, *wks, *p, *ret=numstr;
int i;
wks=wk=strrev(strdup(numstr));
p = strchr(wk, '.');
if(p){//include '.'
while(wk != p)//skip until '.'
*numstr++ = *wk++;
*numstr++=*wk++;
}
for(i=1;*wk;++i){
if(isdigit(*wk)){
*numstr++=*wk++;
if(isdigit(*wk) && i % 3 == 0)
*numstr++ = ',';
} else {
break;
}
}
while(*numstr++=*wk++);
free(wks);
return strrev(ret);
}
int main(){
char buff[64];//To provide a sufficient size after conversion.
sprintf(buff, "%d", 100);
printf("%s\n", commify(buff));
sprintf(buff, "%d", 123456);
printf("%s\n", commify(buff));
sprintf(buff, "%.2f", 1234.56f);
printf("%s\n", commify(buff));
sprintf(buff, "%d", -123456);
printf("%s\n", commify(buff));
sprintf(buff, "%.2lf", -12345678.99);
printf("%s\n", commify(buff));
return 0;
}
ADD:
/*
char *strrev(char *str){
char c,*front,*back;
for(front=str,back=str+strlen(str)-1;front < back;front++,back--){
c=*front;*front=*back;*back=c;
}
return(str);
}
*/
来源:https://stackoverflow.com/questions/10602729/digit-grouping-in-cs-printf