c++: Format number with commas?

C++CommaNumber Formatting

C++ Problem Overview


I want to write a method that will take an integer and return a std::string of that integer formatted with commas.

Example declaration:

std::string FormatWithCommas(long value);

Example usage:

std::string result = FormatWithCommas(7800);
std::string result2 = FormatWithCommas(5100100);
std::string result3 = FormatWithCommas(201234567890);
// result = "7,800"
// result2 = "5,100,100"
// result3 = "201,234,567,890"

What is the C++ way of formatting a number as a string with commas?

(Bonus would be to handle doubles as well.)

C++ Solutions


Solution 1 - C++

Use std::locale with std::stringstream

#include <iomanip>
#include <locale>

template<class T>
std::string FormatWithCommas(T value)
{
    std::stringstream ss;
    ss.imbue(std::locale(""));
    ss << std::fixed << value;
    return ss.str();
}

Disclaimer: Portability might be an issue and you should probably look at which locale is used when "" is passed

Solution 2 - C++

You can do as Jacob suggested, and imbue with the "" locale - but this will use the system default, which does not guarantee that you get the comma. If you want to force the comma (regardless of the systems default locale settings) you can do so by providing your own numpunct facet. For example:

#include <locale>
#include <iostream>
#include <iomanip>

class comma_numpunct : public std::numpunct<char>
{
  protected:
    virtual char do_thousands_sep() const
    {
        return ',';
    }
    
    virtual std::string do_grouping() const
    {
        return "\03";
    }
};

int main()
{
    // this creates a new locale based on the current application default
    // (which is either the one given on startup, but can be overriden with
    // std::locale::global) - then extends it with an extra facet that 
    // controls numeric output.
    std::locale comma_locale(std::locale(), new comma_numpunct());
    
    // tell cout to use our new locale.
    std::cout.imbue(comma_locale);

    std::cout << std::setprecision(2) << std::fixed << 1000000.1234;
}

Solution 3 - C++

I consider the following answer to be easier than the others:

#include <iostream>
int main() {
   int v = 7654321;
   auto s = std::to_string(v);

   int n = s.length() - 3;
   int end = (v >= 0) ? 0 : 1; // Support for negative numbers
   while (n > end) {
      s.insert(n, ",");
      n -= 3;
   }
   std::cout << (s == "7,654,321") << std::endl;
}   

This will quickly and correctly insert commas into your string of digits.

Solution 4 - C++

If you are using Qt, you can use this code:

const QLocale& cLocale = QLocale::c();
QString resultString = cLocale.toString(number);

Also, do not forget to add #include <QLocale>.

Solution 5 - C++

This is pretty old school, I use it in large loops to avoid instantiating another string buffer.

void tocout(long a)
{
    long c = 1;

    if(a<0) {a*=-1;cout<<"-";}
    while((c*=1000)<a);
    while(c>1)
    {
       int t = (a%c)/(c/1000);
       cout << (((c>a)||(t>99))?"":((t>9)?"0":"00")) << t;
       cout << (((c/=1000)==1)?"":",");
    }
}

Solution 6 - C++

based on the answers above, I ended up with this code:

#include <iomanip>
#include <locale> 

template<class T>
std::string numberFormatWithCommas(T value){
    struct Numpunct: public std::numpunct<char>{
    protected:
        virtual char do_thousands_sep() const{return ',';}
        virtual std::string do_grouping() const{return "\03";}
    };
    std::stringstream ss;
    ss.imbue({std::locale(), new Numpunct});
    ss << std::setprecision(2) << std::fixed << value;
    return ss.str();
}

Solution 7 - C++

I found the solution! just copy this to one of your function, this function is written in static function.

// Convert 100000000 to 100,000,000, put commas on the numbers!

std::string AppManager::convertNumberToString(int number) {
    std::string s = std::to_string(number);
    std::string result = "";
    std::string tempResult = "";
    unsigned long n = s.length() - 3;
    int j = 0;
    for (int i=s.size()-1; i>=0; i--) {
        if (j%3 == 0) {
            result.append(",");
        }
        result.append(s, i, 1);
        j++;
    }
    
    result = result.substr(1, result.size()-1);
    
    //now revert back
    for (int i=result.size()-1; i>=0; i--) {
        tempResult.append(result, i, 1);
    }
    
    return tempResult;
}

Here is the result of those code:

click here for seeing the result above!

Solution 8 - C++

I have seen so many ways of doing this, reversing the string(Twice!), using setlocale(sometimes works sometimes not) This is a template solution, I then add explicit specializations. This works for char*, wchar*, string and wstring. I dont translate from numeric to string format here, I highly recommend to_string and to_wstring they are way faster than the 'C' functions such as _itoa etc...

    template<typename T, typename U>
    T StrFormatNumber(const T Data) {
const size_t Length = Data.length();
assert(Length > 0);
// if( 0 == Length ) I would log this and return 
if (Length < 4) { // nothing to do just return
    return Data;
}
constexpr size_t buf_size{ 256 };
assert(((Length)+(Length / 3)) + 1 < buf_size);
if (((Length)+(Length / 3)) + 1 >= buf_size) {
     throw std::invalid_argument( "Input buffer too large" );
}
std::array<U, buf_size > temp_buf{};
auto p{ 0 };
temp_buf[0] = Data[0];
for (auto y{ 1 }; y < Length; y++) {
    if ((Length - y) % 3 == 0) {
        temp_buf[y + p] = ',';
        p++;
    }
    temp_buf[(y + p)] = Data[y];
}
return temp_buf.data();
}
    template<typename T = const char*>
    std::string StrFormatNum(const char* Data) {
        return StrFormatNumber<std::string, char>(std::string(Data));
    }
    template<typename T= std::string>
    std::string StrFormatNum(const std::string Data) {
         return StrFormatNumber<std::string, char>(Data);
     }
    template<typename T = std::wstring>
    std::wstring StrFormatNum( const std::wstring Data) {
        return StrFormatNumber<std::wstring, wchar_t>(Data);
    }
    template<typename T = const wchar_t*>
    std::wstring StrFormatNum( const wchar_t* Data) {
        return StrFormatNumber<std::wstring, wchar_t>(std::wstring(Data));
    }

    void TestStrFormatNumber() {
    	constexpr auto Iterations{ 180 };
    	for (auto l{ 0 }; l < Iterations; l++)
    	{
    		{  // std::string
    			std::string mystr{ "10" };
    			for (int y{ 0 }; y < Iterations; y++) {

    				mystr += "1";
	        		auto p = mystr.length();
			        std::cout << "\r\n  mystr      = " 
                              << std::setw(80) << mystr.c_str()
                              << "\r\n  Length     = "
                              << std::setw(10) << p
                              << "\r\n  modulo % 3 = "
                              << std::setw(10)
                              << p % 3 << "     divided by 3 = "
                              << std::setw(10) << p / 3
                              << "\r\n  Formatted  = " << 
                    StrFormatNum((mystr)).c_str() << "\n";
     			}
    		}
    		{  // std::wstring
    			std::wstring mystr{ L"10" };
                for (int y{ 0 }; y < Iterations; y++)
                {
                     mystr += L"2";
                     auto p = mystr.length();
                     std::wcout << "\r\n  mystr      = "
                                << std::setw(80) << mystr.c_str()
                                << "\r\n  Length     = "
                                << std::setw(10) << p
               					<< "\r\n  modulo % 3 = "
                                << std::setw(10) << p % 3
                                << "     divided by 3 = "
                                << std::setw(10) << p / 3
                                << "\r\n  Formatted  = "
                                << StrFormatNum((mystr)).c_str()
                                << "\n";
               			}
              		}
             		{   // char*
            			std::string mystr{ "10" };
		for (int y{ 0 }; y < Iterations; y++) {
			mystr += "3";
			auto p = mystr.length();
			std::cout << "\r\n  mystr      = " << std::setw(80) << mystr.c_str()
				<< "\r\n	Length     = " << std::setw(10) << p
				<< "\r\n  modulo % 3 = " << std::setw(10) << p % 3 << "     divided by 3 = " << std::setw(10) << p / 3
				<< "\r\n  Formatted  = " << StrFormatNum((mystr.c_str())).c_str() << "\n";
		}
	}
	{  // wchar*
		std::wstring mystr{ L"10" };
		for (int y{ 0 }; y < Iterations; y++) {
			mystr += L"4";
			auto p = mystr.length();
			std::wcout << "\r\n  mystr      = " << std::setw(80) << mystr.c_str()
				<< "\r\n  Length     = " << std::setw(10) << p
				<< "\r\n  modulo % 3 = " << std::setw(10) << p % 3 << "     divided by 3 = " << std::setw(10) << p / 3
				<< "\r\n  Formatted  = " << StrFormatNum((mystr.c_str())).c_str() << "\n";
		}
	} 
}

}

I have tested up to 1,000 spaces(With a larger buffer of course)

Solution 9 - C++

Make another solution:

#include <stdio.h>
#include <string>
#include <stdint.h>
#include <inttypes.h>

std::string GetReadableNum(uint64_t n)
{
    std::string strRet;
    char szTmp[256] = { 0 };
    int ccWritten = sprintf(szTmp, "%" PRIu64 "", n);
    if (ccWritten > 0)
    {
        int nGroup = (ccWritten + 2) / 3;
        int nReminder = ccWritten % 3;
        
        strRet.reserve(ccWritten + (nGroup -1) * 3 + 1);
        const char* p = szTmp;
        for (int i = 0; i < nGroup; i++)
        {
            if (nGroup > 1 && i > 0)
                strRet.append(1, ',');

            for (int c = 0; c < (i > 0 || nReminder == 0 ? 3 : nReminder); c++)
                strRet.append(1, *p++);
        }
    }

    return strRet;
}

int main(int argc, const char* argv[])
{
    uint64_t a = 123456789123ULL;

    std::string s = GetReadableNum(a);

    printf("%s\n", s.c_str());

    return 0;
}

Solution 10 - C++

To make it more flexible, you could construct the facet with a custom thousands sep and grouping string. This way you can set it at runtime.

#include <locale>
#include <iostream>
#include <iomanip>
#include <string>

class comma_numpunct : public std::numpunct<char>
{
public:
   comma_numpunct(char thousands_sep, const char* grouping)
      :m_thousands_sep(thousands_sep),
       m_grouping(grouping){}
protected:
   char do_thousands_sep() const{return m_thousands_sep;}
   std::string do_grouping() const {return m_grouping;}
private:
   char m_thousands_sep;
   std::string m_grouping;
};

int main()
{

    std::locale comma_locale(std::locale(), new comma_numpunct(',', "\03"));

    std::cout.imbue(comma_locale);
    std::cout << std::setprecision(2) << std::fixed << 1000000.1234;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionUserView Question on Stackoverflow
Solution 1 - C++JacobView Answer on Stackoverflow
Solution 2 - C++NodeView Answer on Stackoverflow
Solution 3 - C++carljalalView Answer on Stackoverflow
Solution 4 - C++troView Answer on Stackoverflow
Solution 5 - C++Tom SerinkView Answer on Stackoverflow
Solution 6 - C++Radif SharafullinView Answer on Stackoverflow
Solution 7 - C++Hammy RahardjaView Answer on Stackoverflow
Solution 8 - C++Richard DayView Answer on Stackoverflow
Solution 9 - C++ravin.wangView Answer on Stackoverflow
Solution 10 - C++MarcelView Answer on Stackoverflow