resetear - ¿Cómo formatear un número de 1123456789 a 1.123.456.789 en C?
hard reset motorola moto c (19)
¿Cómo puedo, en lenguaje C, formatear un número del 1123456789
al 1,123,456,789
? Intenté usar printf("%''10d/n", 1123456789);
pero eso no funciona.
¿Podrías aconsejar algo? Cuanto más simple es la solución, mejor.
¡Egads! Hago esto todo el tiempo, usando gcc / g ++ y glibc en Linux y sí, el operador ''puede no ser estándar, pero me gusta su simplicidad.
#include <stdio.h>
#include <locale.h>
int main()
{
int bignum=12345678;
setlocale(LC_ALL,"");
printf("Big number: %''d/n",bignum);
return 0;
}
Da salida de:
Gran número: 12,345,678
Solo hay que recordar la llamada ''setlocale'' allí, de lo contrario no formateará nada.
Aquí está la implementación más delgada, de tamaño y velocidad eficiente de este tipo de formateo de dígitos decimales:
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;
}
Use de la siguiente manera:
char buffer[16];
fprintf (stderr, "test : %s.", formatNumber (1234567890, buffer + 16, true));
Salida:
test : +1,234,567,890.
Algunas ventajas:
Función que toma el final del búfer de cadena debido al formateo ordenado en reversa. Finalmente, donde no es necesario revering cadena generada (strrev).
Esta función produce una cadena que se puede usar en cualquier algo después. No depende ni requiere múltiples llamadas printf / sprintf, lo cual es terriblemente lento y siempre específico al contexto.
- Número mínimo de operadores de división (/,%).
Aquí hay una implementación muy simple. Esta función no contiene ningún error de comprobación, los tamaños del búfer deben ser verificados por la persona que llama. Tampoco funciona para números negativos. Tales mejoras se dejan como un ejercicio para el lector.
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;
}
Basado en @Greg Hewgill, pero toma los números negativos en cuenta y devuelve el tamaño de la cadena.
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);
}
Mi respuesta no formatea el resultado exactamente como en la ilustración de la pregunta, pero puede satisfacer la necesidad real en algunos casos con una sola línea o macro. Uno puede extenderlo para generar más mil grupos según sea necesario.
El resultado buscará, por ejemplo, lo siguiente:
Value: 0''000''012''345
El código:
printf("Value: %llu''%03lu''%03lu''%03lu/n", (value / 1000 / 1000 / 1000), (value / 1000 / 1000) % 1000, (value / 1000) % 1000, value % 1000);
No hay una manera muy simple de hacer esto en C. Simplemente modificaría una función int-to-string para hacerlo:
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);
}
Otra función iterativa
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);
}
}
Puede hacerlo recursivamente de la siguiente manera (tenga cuidado con INT_MIN
si está usando el complemento de dos, necesitará código adicional para administrarlo):
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);
}
Un resumen:
- El usuario llama a
printfcomma
con un entero, el caso especial de números negativos se maneja simplemente imprimiendo "-" y haciendo que el número sea positivo (este es el bit que no funcionará conINT_MIN
). - Cuando ingrese
printfcomma2
, un número menor a 1,000 simplemente imprimirá y devolverá. - De lo contrario, se recurrirá a la recursividad en el siguiente nivel (así se llamará a 1,234,567 con 1,234, luego 1) hasta que se encuentre un número inferior a 1,000.
- Luego se imprimirá ese número y recorreremos nuevamente el árbol de recursión, imprimiremos una coma y el próximo número a medida que avancemos.
También existe una versión más sucinta que procesa innecesariamente los números negativos en todos los niveles (aunque esto no importará dado el número limitado de niveles de recursión). Este es un programa completo para probar:
#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;
}
y el resultado es:
-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
Una solución iterativa para aquellos que no confían en la recursión (aunque el único problema con la recursión tiende a ser el espacio de la pila, que no será un problema aquí, ya que solo tendrá unos pocos niveles, incluso para un entero de 64 bits):
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);
}
}
Ambos generan 2,147,483,647
para INT_MAX
.
Quizás una versión local sería interesante.
#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
Esto tiene un error (pero uno lo consideraría bastante menor). En hardware complementario de dos, no convertirá el número más negativo correctamente, porque intenta convertir un número negativo en su número positivo equivalente con N = -N;
En el complemento a dos, el número máximo negativo no tiene un número positivo correspondiente, a menos que lo promueva a un tipo más grande. Una forma de evitar esto es promoviendo el número correspondiente al tipo sin firmar (pero no es algo trivial).
Se puede hacer con bastante facilidad ...
//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'';
}
Ejemplo de llamada:
char szBuffer[512];
pretty_number("1234567", szBuffer);
//strcmp(szBuffer, "1,234,567") == 0
Secure format_commas, con números negativos:
Como VS <2015 no implementa snprintf, debe hacer esto
#if defined(_WIN32)
#define snprintf(buf,len, format,...) _snprintf_s(buf, len,len, format, __VA_ARGS__)
#endif
Y entonces
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;
}
Ejemplo de uso:
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);
Si su printf es compatible con el ''
flag, probablemente pueda hacerlo simplemente configurando su configuración regional de manera apropiada. Ejemplo:
#include <stdio.h>
#include <locale.h>
int main(void)
{
setlocale(LC_NUMERIC, "");
printf("%''d/n", 1123456789);
return 0;
}
Y construir y ejecutar:
$ ./example
1,123,456,789
Probado en Mac OS X y Linux (Ubuntu 10.10).
Sin recursion o manejo de cadenas, un enfoque matemático:
#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) ) ;
}
}
Similar en principio a la solución recursiva de Pax, pero calculando el orden de magnitud por adelantado, se evita la recursión (quizás a un costo considerable).
Tenga en cuenta también que el carácter real utilizado para separar miles es específico de la configuración regional.
Editar : vea los comentarios de @ Chux a continuación para las mejoras.
Soy nuevo en la programación C. Aquí está mi código simple.
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;
}
Una versión modificada de la solución @paxdiablo, pero usando WCHAR
y 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);
}
otra solución, al guardar el resultado en una matriz int, tamaño máximo si 7 debido a la larga larga int puede manejar el número en el rango de 9,223,372,036,854,775,807 a -9,223,372,036,854,775,807 note it is not an unsigned
función de impresión no recursiva
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]);
}
}
}
}
función principal llamada
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
}
prueba de salida
-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
en la clase principal ()
int numberSeperated[8];
long long int number = 1234567890LL;
getNumWcommas(number, numberSeperated );
si la impresión es necesaria, mueva el número int numberSeperated[8];
dentro de la función getNumWcommas
y llámalo getNumWcommas(number);
// 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'';
}
#include <stdio.h>
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 ...
}
Mi solución usa a. en lugar de a, se le deja al lector cambiar esto.
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<ptr;i++) // print first digits before comma
printf("%c", nstring[i]);
printf(",");
}
j=0;
for (i=ptr;i<m;i++) // print the rest inserting commas
{
printf("%c",nstring[i]);
j++;
if (j%3==0)
if(i<(m-1)) printf(",");
}
}