2010-04-15 10 views
8

Tengo una moneda de clase simple con el operador sobrecargado < <. No sé cómo puedo separar el número con espacios cada 3 dígitos, por lo que se ve así: "1 234 567 ISK".¿Cómo imprimir un número con un espacio como mil separador?

#include <cstdlib> 
#include <iostream> 

using namespace std; 

class Currency 
{ 
    int val; 
    char curr[4]; 

    public: 
    Currency(int _val, const char * _curr) 
    { 
     val = _val; 
     strcpy(curr, _curr); 
    } 

    friend ostream & operator<< (ostream & out, const Currency & c); 
}; 

ostream & operator<< (ostream & out, const Currency & c) 
{ 
    out << c.val<< " " << c.curr; 
    return out; 
} 

int main(int argc, char *argv[]) 
{ 
    Currency c(2354123, "ISK"); 
    cout << c; 
} 

Lo que me interesa, de alguna manera es la solución más fácil para esta situación particular.

+0

@danben: ¿Cómo sería etiquetado como [tarea] cambiar nada acerca de la cuestión o lo bueno respuestas debe ser juzgado? –

+2

@Roger Pate: Etiquetar una pregunta como tarea le permite a la comunidad SO saber que deberían brindar orientación y ayudar al póster a llegar a la solución por sí mismo en lugar de solo escribirle la solución. Ver http://meta.stackexchange.com/questions/10811/how-to-ask-and-answer-homework-questions. – danben

+0

@danben: ver http://meta.stackexchange.com/questions/10811/how-to-ask-and-answer-homework-questions/10825#10825 y http://meta.stackexchange.com/questions/10811/how-to-ask-and-answer-tarea-preguntas/10839 # 10839 –

Respuesta

15

Esto se puede hacer con facetas

struct myseps : numpunct<char> { 
    /* use space as separator */ 
    char do_thousands_sep() const { return ' '; } 

    /* digits are grouped by 3 digits each */ 
    string do_grouping() const { return "\3"; } 
}; 

int main() { 
    std::cout.imbue(std::locale(std::locale(), new myseps)); 
    std::cout << 10000; // 10 000 
} 

Alternativamente, es posible que el código de su propio bucle

void printGrouped(ostream &out, int n) { 
    if(n < 0) { 
    out << "-"; 
    return printGrouped(out, -n); 
    } 

    if(n < 1000) { 
    out << n; 
    } else { 
    printGrouped(out, n/1000); 
    out << " " << setw(3) << setfill('0') << (n % 1000); 
    } 
} 

ostream & operator<< (ostream & out, const Currency & c) { 
    printGrouped(out, c.val); 
    out << " " << c.curr; 
    return out; 
} 
+0

Aunque cambiar cómo se imprimen * todos los números * es casi seguro que no se desea. –

+0

@Roger fair point. Se agregó un bucle personalizado. –

+0

'locale (" ")' está definido por la implementación. en OS X 10.5 no funcionará (arroja una 'runtime_exception' con' what() '" locale :: facet :: _ S_create_c_locale nombre no válido "). Puede utilizar la configuración regional global actual con el constructor predeterminado en su lugar. – wilhelmtell

2
struct Currency { 
    static char const sep = ' '; 
    static int const group_size = 3; 

    Currency(int val, std::string unit) 
    : val(val), unit(unit) 
    {} 

    friend std::ostream& operator<<(std::ostream& out, Currency const& v) { 
    // currently ignores stream width and fill 
    std::ostringstream ss; 
    bool const neg = v.val < 0; 
    int const val = (neg ? -v.val : v.val); 
    if (neg) out << '-'; 
    ss << val; 
    std::string const s = ss.str(); 
    std::string::size_type n = s.size() % v.group_size; 
    if (n) out << s.substr(0, n); 
    for (; n < s.size(); n += v.group_size) { 
     out << sep << s.substr(n, v.group_size); 
    } 
    out << ' ' << v.unit; 
    return out; 
    } 

private: 
    int val; 
    std::string unit; 
}; 

podría hacer SEP y GROUP_SIZE miembros no estáticos, si desea personalizar cada objeto con comas, etc. (Si es así, que sean privadas e inicializar en el ctor, probablemente con valores de los parámetros por defecto.) Usted también podría usar una clase de rasgos que controle el formato de salida.

Las configuraciones regionales también admiten el formato de moneda a través de la faceta moneypunct.

7

Una posibilidad podría ser la de utilizar locales para esto.

#include <locale> 
#include <string> 
#include <cstddef> 

class SpaceSeparator: public std::numpunct<char> 
{ 
public: 
    SpaceSeparator(std::size_t refs): std::numpunct<char>(refs) {} 
protected: 
    char do_thousands_sep() const { return ' '; } 
    std::string do_grouping() const { return "\03"; } 
}; 

//...  
ostream & operator<< (ostream & out, const Currency & c) 
{ 
    SpaceSeparator facet(1); //1 - don't delete when done 
    std::locale prev = out.imbue(std::locale(std::locale(), &facet)); 
    out << c.val<< " " << c.curr; 
    out.imbue(prev); //restore previous locale 
    return out; 
} 
+0

+1 para una solución de entorno local más limpio :) –

+1

Sin embargo, std :: moneypunct sería una mejor opción para usar. –

-1
#include <iostream> 

#include <sstream> 

#include <cstdlib> 

#define GROUP_SEP ',' 

#define GROUP_SIZE 3 

using namespace std; 

string output_formatted_string(long long num); 


int main() { 

    string temp; 

    cout << "Enter a large number: "; 

    getline(cin, temp); 

    long long num = atoll(temp.c_str()); 

    string output = output_formatted_string(num); 


    cout << output << endl; 

    return 0; 

    } 

    string output_formatted_string(long long num) 

    { 

    stringstream temp, out; 

    temp << num; 

    string s = temp.str(); 


    int n = s.size() % GROUP_SIZE; 

    int i = 0; 

    if(n>0 && s.size() > GROUP_SIZE) 

     { 

     out << s.substr(i, n) << GROUP_SEP; 

     i += n; 

     } 


    n = s.size()/GROUP_SIZE - 1; 

    while(n-- > 0) 
     { 

     out << s.substr(i, GROUP_SIZE) << GROUP_SEP; 

     i += GROUP_SIZE;   
} 

    out << s.substr(i); 

    return out.str(); 

    } 
Cuestiones relacionadas