Formatting an integer in C++

2020-08-20 04:18发布

问题:

I have an 8 digit integer which I would like to print formatted like this:

XXX-XX-XXX

I would like to use a function that takes an int and returns a string.

What's a good way to do this?

回答1:

This is how I'd do it, personally. Might not be the fastest way of solving the problem, and definitely not as reusable as egrunin's function, but it strikes me as both clean and easy to understand. I'll throw it in the ring as an alternative to the mathier and loopier solutions.

#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, "-");
};


回答2:

Tested this, it works.

The format parameter here is "XXX-XX-XXX", but it only looks at (and skips over) the dashes.

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

Usage:

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

    return 0;
}


回答3:

Here's a bit different way that tries to work with the standard library and get it to do most of the real work:

#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

To return a string, just write to a stringstream, and return its .str().

This may be overkill if you only want to print out one number that way, but if you want to do this sort of thing in more than one place (or, especially, if you want to format all numbers going to a particular stream that way) it becomes more reasonable.



回答4:

Here's a complete program that shows how I'd do it:

#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 this with certain inputs gives:

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

Those last two show the importance of testing. If you want different behaviour, you'll need to modify the code. I generally opt for silent enforcement of rules if the caller can't be bothered (or is too stupid) to follow them but apparently some people like to use the principle of least astonishment and raise an exception :-)



回答5:

You can use the std::ostringstream class to convert the number to a string. Then you can use the string of digits and print them using whatever formatting you want, as in the following code:

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
}


回答6:

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

Its not a function, but its a general method for parsing an int number by number.



回答7:

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


回答8:

How's this?

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

Edit 1: I see strstream is deprecated and replaced with stringstream.

Edit 2: Fixed issue of missing leading 0's. I know, it's ugly.



回答9:

Obviously a char * and not a string, but you get the idea. You'll need to free the output once you're done, and you should probably add error checking, but this should do it:

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


回答10:

You don't require malloc or new, just define buf as char buff[11];



标签: c++ string g++