¿Como formatear un numero con comas en C++?

Tenia pensado escribir sobre lo que estoy haciendo, pero hoy no tengo cabeza para eso, así que me he puesto en modo automático y les traigo un poco de código.

Problema: Convertir un numero a cadena, insertando comas en cada millar y truncando hasta las decimales.

C++ es un lenguaje muy poderoso, pero a veces cuando se trata de hacer cosas que son muy sencillas en otros lenguajes C++ no hace mas que resistirse. Claro que podríamos ocupar una librería que nos resuelva las cosas, siempre cuidando que sea multiplataforma y que sea opensource y de preferencia que ya este compilada, por ejemplo Boost, la cual recomiendo ampliamente. Pero no parece ser buena idea ocupar una librería para algo que inicialmente parece sencillo.

Entonces te pones a escribir código …

#include
#include 
using namespace std;
 
string ponleComas(double Numero)
{
	stringstream flujo;
	flujo << fixed << Numero;
	string s = flujo.str();
 
	string ns;
		if (s.find(".") != string::npos) {
		ns = s.substr(s.find("."), 3);
		s = s.substr(0, s.find("."));
	}
 
	int c = 0;
	for (int i=s.length()-1; i>=0; i--) {
		if (c % 3 == 0 && c != 0) {
			ns = "," + ns;
		}
		c++;
		ns = s[i] + ns;
	}
	return ns;
}

Listo, se usa así:

	double x = 950123.8384;
	double y = 83838347.123;
	double z = 45027456475345.56345;
 
	cout << ponleComas (x) << endl;
	cout << ponleComas (y) << endl;
	cout << ponleComas (z) << endl;

ESPERA!!! , tranquilo, no copies código aun. ¿Por que hacernos la vida fácil? Aquí va la segunda versión de este código:

#include 
#include 
#include 
class coma_numpunct : public std::numpunct
{
	protected:
	virtual char do_thousands_sep() const { return ','; }
	virtual std::string do_grouping() const { return "\03"; }
};
 
string ponleComas2 (double Numero)
{
	locale coma_locale(locale(), new coma_numpunct());
	stringstream flujo;
	flujo.imbue(coma_locale);
	flujo << setprecision(2) << Numero;
	string s = flujo.str();
	return s;
}

Mira que bonito código !! se ve bien PRO … y ademas funciona 😀

¿Y como funciona? Pues lo primero que vemos es la clase coma_numpunct la cual sobre escribe algunos metodos de la clase numpunct, si juegas un poco puedes cambiar el caracter de separacion y el numero de caracteres que van entre una coma y la siguiente.

Luego, en la función ponleComas2, instanciamos un objeto de tipo locale y usamos en el constructor una instancia de la clase coma_numpunct que habiamos creado anteriormente.

Los objetos locale definen varias características de la forma en que se presentan los datos, con respecto a la cultura. Por ejemplo en algunos países se usa el punto en lugar de la coma para separar las decimales, o en las fechas se pone el mes/dia/año en lugar de dia/mes/año.

Creamos un objeto de tipo stringstream, que nos sirve como una especie de buffer, en el cual podemos imprimir cosas como si fuera cout, pero no se imprimiran en pantalla.

Ahora viene la impresion del numero, y vemos que aparece un setprecision(2) que es muy obvio y ademas un fixed que evita que se use la notacion cientifica, ya sabes 9.5e+05 en lugar de 950,123.83.

Finalmente usamos el método str() para convertir el stringstream a string y retornamos el valor.

Seria muy interesante medir tiempos, para ver cual de las dos implementaciones funciona mejor, pero eso ya es de verdad no tener nada que hacer :P. Espero que el código les sirva. Si conocen otra forma de hacerlo póngalo en los comentarios, sera interesante darle un vistazo.

 

 

Eric Ruiz Osornio (Zeru). Instituto Politécnico Nacional, México. Gamer de StarCraft2, coder y administrador de proyectos.

Facebook Twitter 

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *