This function reformats a numeric sequence to include grouping in the usual human readable format. "123456789" becomes "123,456,789", for example. The formatting is localized to the current running machine. In a German locale the previous example becomes "123.456.789". In a Hindi locale it becomes "12,34,56,789". Printing numbers for human consumption is a common request. C does not offer direct support for it, nor are there many examples that are complete for use outside of the US that I could find.
Formatting numeric values with commas
Adak commented: Looks very robust - well done. +3
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <locale.h>
#include <ctype.h>
typedef enum { FALSE, TRUE } BOOL;
struct locale {
struct lconv* settings;
char* previous;
};
static struct locale change_locale(int category, char const* name) {
struct locale loc;
loc.previous = setlocale(category, NULL);
setlocale(category, name);
loc.settings = localeconv();
return loc;
}
BOOL format_numeric(char const* num, char* buf, int buf_sz) {
struct locale loc = change_locale(LC_NUMERIC, "");
int group_sz = 0, sep_sz = strlen(loc.settings->thousands_sep);
char* group = loc.settings->grouping;
int x = strlen(num)-1, y = 0;
while (x >= 0) { // copy num backwards into buf
if (!isdigit(num[x]) || y >= buf_sz-1)
return FALSE;
if (*group == CHAR_MAX || group_sz++ != *group) {
// verbatim copy, no grouping or still within a group
buf[y++] = num[x--];
}
else {
// terminate group with group separator
memcpy(buf + y, loc.settings->thousands_sep, sep_sz);
if (group != loc.settings->grouping && *(group+1) != 0)
++group;
group_sz = 0;
y += sep_sz;
}
}
buf[y] = '\0';
// the string was built backwards. reverse it here
for (x = 0; x < --y; ++x) {
char tmp = buf[x];
buf[x] = buf[y];
buf[y] = tmp;
}
setlocale(LC_NUMERIC, loc.previous); // restore original locale
return TRUE;
}
void main() {
char input[BUFSIZ], output[BUFSIZ];
do {
printf("enter a number> ");
if (fgets(input, BUFSIZ, stdin)) {
int len = strlen(input);
if (len > 0 && input[len-1] == '\n')
input[len-1] = '\0';
if (format_numeric(input, output, BUFSIZ))
printf("|%s|\n", output);
else
fprintf(stderr, "conversion error for '%s'\n", input);
}
} while (!feof(stdin));
}
Be a part of the DaniWeb community
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.