76

我想编写一个方法,该方法将采用一个整数并返回一个std::string用逗号格式化的整数。

示例声明:

std::string FormatWithCommas(long value);

示例用法:

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"

将数字格式化为string带逗号的 C++ 方法是什么?

(奖励也是处理doubles 。)

4

10 回答 10

59

std::locale与_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();
}

免责声明:可移植性可能是一个问题,您可能应该查看""传递时使用的语言环境

于 2011-09-01T21:38:23.743 回答
56

您可以按照 Jacob 的建议进行操作,并imbue使用""区域设置 - 但这将使用系统默认值,这并不能保证您得到逗号。如果您想强制使用逗号(无论系统默认区域设置如何),您可以通过提供您自己的numpunct方面来实现。例如:

#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;
}
于 2011-09-01T22:28:56.120 回答
39

我认为以下答案比其他答案更容易:

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

这将快速正确地将逗号插入您的数字字符串中。

于 2014-06-12T19:48:32.370 回答
2

如果您使用的是 Qt,则可以使用以下代码:

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

另外,不要忘记添加#include <QLocale>.

于 2015-07-21T17:18:32.860 回答
2

这是相当古老的学校,我在大循环中使用它以避免实例化另一个字符串缓冲区。

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)?"":",");
    }
}
于 2016-06-10T18:36:41.920 回答
1

根据上面的答案,我最终得到了这段代码:

#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();
}
于 2013-09-06T17:55:07.470 回答
1

我找到了解决方案!只需将其复制到您的一个函数中,此函数是用静态函数编写的。

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

以下是这些代码的结果:

点击这里查看上面的结果!

于 2022-01-09T05:28:24.480 回答
1

我见过很多这样做的方法,反转字符串(两次!),使用 setlocale(有时有效,有时无效)这是一个模板解决方案,然后我添加了明确的专业化。这适用于 char*、wchar*、string 和 wstring。我不在这里将数字格式转换为字符串格式,我强烈推荐 to_string 和 to_wstring 它们比 _itoa 等“C”函数快得多...

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

}

我已经测试了多达 1,000 个空格(当然有更大的缓冲区)

于 2022-01-29T03:14:18.223 回答
0

做另一个解决方案:

#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;
}
于 2021-09-12T11:08:47.760 回答
-1

为了使其更灵活,您可以使用自定义的千位 sep 和分组字符串来构建构面。这样您就可以在运行时设置它。

#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;
}
于 2015-06-16T01:47:54.777 回答