2010-05-12 40 views

Odpowiedz

11

Tak to zrobię, osobiście. Być może nie jest to najszybszy sposób rozwiązania problemu i zdecydowanie nie nadaje się do ponownego użycia jako funkcja egrunin, ale wydaje mi się, że jest zarówno czysty, jak i łatwy do zrozumienia. Wrzucę to na ringu jako alternatywę dla rozwiązań matematycznych i pętlowych.

#include <sstream> 
#include <string> 
#include <iomanip> 

std::string format(long num) { 
    std::ostringstream oss; 
    oss << std::setfill('0') << std::setw(8) << num; 
    return oss.str().insert(3, "-").insert(6, "-"); 
}; 
+0

zdecydowanie najłatwiej zrozumieć (czyli przeczytać) wszystkie odpowiedzi. – Inverse

1
int your_number = 12345678; 

std::cout << (your_number/10000000) % 10 << (your_number/1000000) % 10 << (your_number/100000) %10 << "-" << (your_number/10000) %10 << (your_number/1000) %10 << "-" << (your_number/100) %10 << (your_number/10) %10 << (your_number) %10; 

http://www.ideone.com/17eRv

nie jego funkcji, ale jego ogólny sposób analizowania numer int przez liczbę.

3

Możesz użyć klasy std :: ostringstream, aby przekonwertować liczbę na łańcuch. Następnie możesz użyć ciągu cyfr i wydrukować je przy użyciu dowolnego formatowania, zgodnie z poniższym kodem:

std::ostringstream oss; 
oss << std::setfill('0') << std::setw(8) << number; 
std::string str = oss.str(); 
if (str.length() != 8){ 
    // some form of handling 
}else{ 
    // print digits formatted as desired 
} 
1

Jak to jest?

std::string format(int x) 
{ 
    std::stringstream ss 

    ss.fill('0'); 
    ss.width(3); 
    ss << (x/10000); 

    ss.width(1); 
    ss << "-"; 

    ss.width(2); 
    ss << (x/1000) % 100; 

    ss.width(1); 
    ss << "-"; 

    ss.width(3); 
    ss << x % 1000; 

    return ss.str(); 
}

Edycja 1: Widzę strstream jest przestarzała i zastąpiona stringstream.

Edytuj 2: Naprawiono problem braku wiodących zer. Wiem, to brzydkie.

0

Oczywiście jest to char *, a nie string, ale masz pomysł. Po zakończeniu pracy musisz zwolnić dane wyjściowe i prawdopodobnie powinieneś dodać kontrolę błędów, ale powinno to zrobić:

char * formatter(int i) 
{  
    char *buf = malloc(11*sizeof(char)); 
    sprintf(buf, "%03d-%02d-%03d", i/100000, (i/1000)%100, i%1000); 
    return buf; 
} 
+1

dlaczego malloc, jesteśmy w C++ tutaj –

+1

Dlaczego ręczny przydział? Jeśli cokolwiek, uczyń bufor automatycznie, a nie dynamicznie ('sizeof (char)' jest zawsze 1, stwórz bufor 16, tylko dlatego, że jest ładnym numerem), 'sprintf' do tego, a następnie zwróć' std :: string'. – GManNickG

6

Sprawdzone, działa.

Parametr format to "XXX-XX-XXX", ale analizuje tylko (i pomija) myślniki.

std::string foo(char *format, long num) 
{ 
    std::string s(format); 

    if (num < 0) { return "Input must be positive"; } 

    for (int nPos = s.length() - 1; nPos >= 0; --nPos) 
    { 
     if (s.at(nPos) == '-') continue; 

     s.at(nPos) = '0' + (num % 10); 
     num = num/10; 
    } 

    if (num > 0) { return "Input too large for format string"; } 

    return s; 
} 

Zastosowanie:

int main() 
{ 
    printf(foo("###-##-###", 12345678).c_str()); 

    return 0; 
} 
+0

+1, aby uzyskać bardziej ogólne rozwiązanie. – andand

+1

+0 za naruszenie YAGNI :-) – paxdiablo

+3

Ale co robi "cout << foo (" ### - ## ", 12345) << endl'? Jeśli funkcja ma działać tylko z określoną długością ciągu formatu, powinieneś to "potwierdzić". IMO powinieneś "zapewnić" warunki zasięgu, a nie po cichu. – msandiford

4

Oto kompletny program, który pokazuje, jak zrobiłbym to:

#include <iostream> 
#include <iomanip> 
#include <sstream> 

std::string formatInt (unsigned int i) { 
    std::stringstream s; 
    s << std::setfill('0') << std::setw(3) << ((i % 100000000)/100000) << '-' 
     << std::setfill('0') << std::setw(2) << ((i % 100000)/1000) << '-' 
     << std::setfill('0') << std::setw(3) << (i % 1000); 
    return s.str(); 
} 

int main (int argc, char *argv[]) { 
    if (argc > 1) 
     std::cout << formatInt (atoi (argv[1])) << std::endl; 
    else 
     std::cout << "Provide an argument, ya goose!" << std::endl; 
    return 0; 
} 

Running to z pewnych nakładów daje:

Input  Output 
--------  ---------- 
12345678  123-45-678 
0   000-00-000 
7012   000-07-012 
10101010  101-01-010 
123456789 234-56-789 
-7   949-67-289 

Te dwie ostatnie wskazują na znaczenie testowania . Jeśli chcesz innego zachowania, musisz zmodyfikować kod. I ogólnie zdecydować się na cichym egzekwowania przepisów, jeśli rozmówca nie może być jedno (lub jest zbyt głupi), aby ich przestrzegać, ale najwyraźniej niektórzy ludzie lubią używać zasadę najmniejszego zdziwienia i podnieść wyjątek :-)

1
#include <iostream> 
#include <string> 

using namespace std; 

template<class Int, class Bi> 
void format(Int n, Bi first, Bi last) 
{ 
    if(first == last) return; 
    while(n != 0) { 
     Int t(n % 10); 
     n /= 10; 
     while(*--last != 'X' && last != first); 
     *last = t + '0'; 
    } 
} 

int main(int argc, char* argv[]) 
{ 
    int i = 23462345; 
    string s("XXX-XX-XXX"); 
    format(i, s.begin(), s.end()); 
    cout << s << endl; 
    return 0; 
} 
+0

Ten algorytm będzie działał z dowolną liczbą całkowitą, o ile ciąg znaków formatowania ma liczbę X równą długości liczby całkowitej. Na przykład w przypadku liczby całkowitej z 8 cyframi ciąg znaków musi składać się z 8 znaków X. – wilhelmtell

+0

Dlatego może być lepiej zakończyć na podstawie 'first == last' zamiast' n == 0'. –

5

Oto nieco odmienny sposób, że stara się pracować z biblioteki standardowej i zmusić go do zrobienia najbardziej realnej pracy:

#include <locale> 

template <class T> 
struct formatter : std::numpunct<T> { 
protected: 
    T do_thousands_sep() const { return T('-'); } 
    std::basic_string<T> do_grouping() const { 
     return std::basic_string<T>("\3\2\3"); 
    } 
}; 

#ifdef TEST 

#include <iostream> 

int main() { 
    std::locale fmt(std::locale::classic(), new formatter<char>); 
    std::cout.imbue(fmt); 

    std::cout << 12345678 << std::endl; 
    return 0; 
} 

#endif 

aby powrócić ciąg, po prostu napisz do stringstream, i zwraca jego .str().

Może to być przesada, jeśli chcesz wydrukować tylko jeden numer w ten sposób, ale jeśli chcesz robić tego rodzaju rzeczy w więcej niż jednym miejscu (lub, szczególnie, jeśli chcesz sformatować , wszystkie numery będą do określonego strumienia w ten sposób) staje się bardziej rozsądny.

+3

Naprawdę nie widzę zbyt wielu ludzi, którzy rozwiązują ten konkretny problem w ten sposób, ale +1 za najbardziej niesamowitą odpowiedź. – msandiford

-1

Nie wymaga malloc lub new, wystarczy zdefiniować buf jak char buff[11];

Powiązane problemy