2010-04-15 9 views
8

Mam prostą walutę klasy z przeciążonym operatorem < <. Nie wiem, jak mogę oddzielić tę liczbę spacjami co 3 cyfry, więc wygląda to tak: "1 234 567 ISK".Jak wydrukować liczbę z odstępem jako separatorem tysięcy?

#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; 
} 

Co mnie interesuje, jest jakoś najłatwiejszym rozwiązaniem w tej konkretnej sytuacji.

+0

@danben: Jak tagowanie go jako [praca domowa] zmienia nic o pytanie czy jak dobre odpowiedzi powinny być oceniane? –

+2

@Roger Pate: Oznaczanie pytania jako zadania domowe pozwala wspólnocie SO wiedzieć, że powinni oni udzielać wskazówek i pomagać plakatowi w samodzielnym rozwiązaniu problemu, zamiast pisać rozwiązanie dla niego. Zobacz http://meta.stackexchange.com/questions/10811/how-to-ask-and-answer-homework-questions. – danben

+0

@danben: Zobacz http://meta.stackexchange.com/questions/10811/how-to-ask-and-answer-homework-questions/10825#10825 i http://meta.stackexchange.com/questions/10811/how-to-ask-and-answer-homework-questions/10839 # 10839 –

Odpowiedz

15

Można to zrobić z aspektów

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 
} 

Alternatywnie, można kodować własne pętla

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

Chociaż zmiana sposobu drukowania * wszystkich * liczb jest prawie na pewno niepożądana. –

+0

@Roger fair point. Dodano niestandardową pętlę. –

+0

'locale (" ")' jest zdefiniowane przez implementację. na OS X 10.5 nie będzie działać (zgłasza wyrażenie runtime_exception z 'what()' "nazwa_lokalna :: facet :: _ S_create_c_locale nazwa nie jest poprawna"). Zamiast tego można użyć bieżącego globalnego ustawienia narodowego z domyślnym konstruktorem. – 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; 
}; 

można zrobić SEP i GROUP_SIZE członków non-statycznych, jeśli chcesz, aby dostosować każdy obiekt z przecinkiem itp (Jeśli tak, to ich prywatna i zainicjować w ctor, prawdopodobnie z wartościami parametrów domyślnych.), Które może również użyć klasy cech kontrolujących formatowanie wyjściowe.

Ustawienia lokalne obsługują także formatowanie walut za pośrednictwem aspektu "moneypunct".

7

Jedną z możliwości może być użycie locales do tego.

#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 dla czystszego rozwiązania lokalizacyjnego :) –

+1

Jednak std :: moneypunct byłoby lepszym rozwiązaniem. –

-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(); 

    } 
Powiązane problemy