在 C++ 中使用逗号格式化数字

发布于 2024-12-02 16:47:34 字数 493 浏览 0 评论 0原文

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

声明示例:

std::string FormatWithCommas(long value);

用法示例:

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

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

(额外的好处是还可以处理 double 。)

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 result1 = FormatWithCommas(7800);
std::string result2 = FormatWithCommas(5100100);
std::string result3 = FormatWithCommas(201234567890);
// result1 = "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.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

千仐 2024-12-09 16:47:34

使用 std::localestd::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();
}

免责声明: 可移植性可能是一个问题并且您可能应该查看传递 "" 时使用的区域设置

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

夏末的微笑 2024-12-09 16:47:34

您可以按照 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;
}

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;
}
我三岁 2024-12-09 16:47:34

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

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

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

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.

挽心 2024-12-09 16:47:34

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

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

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)?"":",");
    }
}
萌逼全场 2024-12-09 16:47:34

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

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

另外,不要忘记添加 #include

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>.

忘你却要生生世世 2024-12-09 16:47:34

正确的解决方案是

struct comma_out : std::numpunct<char>
{
    char do_thousands_sep()   const { return ','; }  // separate with spaces
    std::string do_grouping() const { return "\3"; } // groups of 3 digit
};
 
int main()
{
    std::cout << "default locale: " << 12345678 << '\n';
    std::cout.imbue(std::locale(std::cout.getloc(), new comma_out));
    std::cout << "locale with modified numpunct: " << 12345678 << '\n';
}

您不能使用 std::fixed - 它仅适用于浮点

Right solution is

struct comma_out : std::numpunct<char>
{
    char do_thousands_sep()   const { return ','; }  // separate with spaces
    std::string do_grouping() const { return "\3"; } // groups of 3 digit
};
 
int main()
{
    std::cout << "default locale: " << 12345678 << '\n';
    std::cout.imbue(std::locale(std::cout.getloc(), new comma_out));
    std::cout << "locale with modified numpunct: " << 12345678 << '\n';
}

YOU MUST NOT USE std::fixed - it's only for floating point

用心笑 2024-12-09 16:47:34

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

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

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();
}
说不完的你爱 2024-12-09 16:47:34

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

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

以下是这些代码的结果:

单击此处查看上面的结果!

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!

白昼 2024-12-09 16:47:34

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

    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 个空格(当然有更大的缓冲区)

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)

风轻花落早 2024-12-09 16:47:34

这是获得您所要求的内容的非常简单的方法。您将需要一个 long long 来处理 result3 201+ 十亿。函数 formatWithCommas() 接受一个 long long 并返回一个格式化字符串,每隔三个小数位有一个逗号。使用标准字符串库中的字符串方法 to_string() 将数字转换为字符串。然后使用 string.length() 获取数字字符串的长度。设置一个 for 循环,从字符串长度减三开始。使用字符串库 insert() 中的另一个函数,在递减 3 时,每隔三个位置放置一个逗号,i -= 3。请注意,我使用字符串“,”而不是字符“,”。如果不更改数据类型,则只需要两个参数,即索引和在本例中的子字符串。如果更改数据类型,则需要使用第三个参数来说明要从给定索引开始放置多少个字符。下面是一个示例,str.insert(i, ",") 或 str.insert(i, ',', 1)。循环的条件部分 i > 0 将阻止循环在少于四个字符的字符串上运行,因为 str.length() -3 必须至少为 4,才能在 i > 时使 i 等于 1。 0 为真实陈述。

如果您需要使用可能的负数,您可以在 for 循环之前设置一个 bool 标志并操作索引零,并在正确放置逗号之后插入负号 - 返回格式化的数字字符串。

/*
Program:Format Number With Comma
Author:Phillip McCullough
Date:1/29/2023
C/Cpp:11+ ANSI Standard

This program uses the function formatWithCommas() to add one or more commas at
every third decimal place as conventional written formatting includes.
-------10--------20--------30--------40--------50--------60--------70--------80
*/
#include <iostream> 
#include <string> 

std::string formatWithCommas(long long number);

int main()
{ 
    std::cout << formatWithCommas(7800) << '\n'// result1 = 7,800
        << formatWithCommas(5100100) << '\n'// result2 = 5,100,100
        << formatWithCommas(201234567890) << '\n';// result3 = 201,234,567,890

    return 0;
}

// ---------------------------------------------------------------------------- 

std::string formatWithCommas(long long number)
{
    std::string number_str = std::to_string(number);

    for (int i = number_str.length() - 3; i > 0; i -= 3)
        number_str.insert(i, ",");

    return number_str;
}

// ----------------------------------------------------------------------------

Here is a very simple way to get what you are asking for. You will need a long long to handle result3 201+ billion. The function formatWithCommas() takes in a long long and returns a formatted string with commas at every third decimal place. Use string method to_string() from the standard string library to convert your number to a string. Then use string.length() to get the length of your numeric string. Setup a for loop that starts at the length of your string minus three. Use another function from the string library insert() to place a comma at every third position as you decrement by three, i -= 3. Notice that I use a string "," instead of a character ','. If you don't change datatypes you only need two arguments, the index and in this case a sub-string. If you change datatypes you will need to use a third argument to state how many characters you want to place starting at the given index. Here is an example, str.insert(i, ",") or str.insert(i, ',', 1). The conditional section of your loop i > 0 will prevent the loop from running on a string with less than four characters as str.length() -3 must be at least four to start with making i equal to one for i > 0 to be a true statement.

If you need to work with possibly negative numbers you can set a bool flag and manipulate index zero before the for loop and insert the negative symbol - back after the commas have been correctly placed before returning the formatted numeric string.

/*
Program:Format Number With Comma
Author:Phillip McCullough
Date:1/29/2023
C/Cpp:11+ ANSI Standard

This program uses the function formatWithCommas() to add one or more commas at
every third decimal place as conventional written formatting includes.
-------10--------20--------30--------40--------50--------60--------70--------80
*/
#include <iostream> 
#include <string> 

std::string formatWithCommas(long long number);

int main()
{ 
    std::cout << formatWithCommas(7800) << '\n'// result1 = 7,800
        << formatWithCommas(5100100) << '\n'// result2 = 5,100,100
        << formatWithCommas(201234567890) << '\n';// result3 = 201,234,567,890

    return 0;
}

// ---------------------------------------------------------------------------- 

std::string formatWithCommas(long long number)
{
    std::string number_str = std::to_string(number);

    for (int i = number_str.length() - 3; i > 0; i -= 3)
        number_str.insert(i, ",");

    return number_str;
}

// ----------------------------------------------------------------------------
零度℉ 2024-12-09 16:47:34

提出另一个解决方案:

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

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;
}
血之狂魔 2024-12-09 16:47:34

根据上面 Jacob 的回答...

这是一个 Windows 解决方案。

// Compiler : Visual Studio 2022
// I tested on Windows 10 64bit
// DATE: 2022.Sep.15

#include <windows.h>
#include <string>
#include <locale>
#include <sstream>

using namespace std;

template<class T>
std::string FormatWithCommas(T value)
{    
    std::stringstream ss;

    // otherwise, use "en_US.UTF-8" as the locale name
    ss.imbue(std::locale("ko_KR.UTF-8"));
    ss << std::fixed << value;

    return ss.str();
}

int main()
{
    LARGE_INTEGER filesize;

    filesize.QuadPart = 1234591046976109;

    // This only works for ASCII strings
    string aaa = (FormatWithCommas(filesize.QuadPart)).c_str();
    std::wstring widestr = std::wstring(aaa.begin(), aaa.end());
    const wchar_t* widecstr = widestr.c_str();

    wprintf_s(L"\nFile Size =  %s bytes\n", widecstr);

    getchar();
    return 0;
}

执行结果如下。

执行结果如下。

Based on Jacob's answer above...

This is a Windows solution.

// Compiler : Visual Studio 2022
// I tested on Windows 10 64bit
// DATE: 2022.Sep.15

#include <windows.h>
#include <string>
#include <locale>
#include <sstream>

using namespace std;

template<class T>
std::string FormatWithCommas(T value)
{    
    std::stringstream ss;

    // otherwise, use "en_US.UTF-8" as the locale name
    ss.imbue(std::locale("ko_KR.UTF-8"));
    ss << std::fixed << value;

    return ss.str();
}

int main()
{
    LARGE_INTEGER filesize;

    filesize.QuadPart = 1234591046976109;

    // This only works for ASCII strings
    string aaa = (FormatWithCommas(filesize.QuadPart)).c_str();
    std::wstring widestr = std::wstring(aaa.begin(), aaa.end());
    const wchar_t* widecstr = widestr.c_str();

    wprintf_s(L"\nFile Size =  %s bytes\n", widecstr);

    getchar();
    return 0;
}

The execution result is as follows.

The execution result is as follows.

离旧人 2024-12-09 16:47:34

受到 @carljalal 答案的启发,我使用反向迭代器找到了一个类似但不同的答案。可能效率较低,但更紧凑:

#include <string>
#include <iterator>
#include <cctype>  // for isdigit
...

void addCommas(std::string& num)
{
   // begin at the 3rd digit from the back, advance 3 each time
   for (auto it = str.rbegin()+3; it < str.rend(); it += 3)
   {
      // this handles a negative sign (ignores it)
      if (isdigit(*it))
      {
         // there are currently no string functions dealing with reverse_iterators,
         // so use .base() to get it's corresponding forward_iterator

         // inserting into a string invalidates any iterators, so "reset" `it`, and
         // we have to make the return value into a reverse_iterator
         it = std::make_reverse_iterator(str.insert(it.base(), ','));
      }
   }
}

注意,有 使用 .base() 时有些谨慎,但对于我尝试的输入来说,一切似乎都很好。上面处理任何长度的数字字符串,无论前面有或没有负号,但不处理小数。另请注意, std::make_reverse_iterator 需要 c ++14 或更高版本。

一些示例输入和输出:

1 ==>                  1
12 ==>                 12
123 ==>                123
-12 ==>               -12
-123 ==>              -123
1234 ==>               1,234
-1234 ==>             -1,234
12134 ==>              12,134
-12134 ==>            -12,134
328947328949893 ==>    328,947,328,949,893
-328947328949893 ==>  -328,947,328,949,893
9328947328949893 ==>   9,328,947,328,949,893
-9328947328949893 ==> -9,328,947,328,949,893

演示

Inspired by @carljalal's answer, I found a similar-but-different answer using reverse iterators. Probably less efficient, but a bit more compact:

#include <string>
#include <iterator>
#include <cctype>  // for isdigit
...

void addCommas(std::string& num)
{
   // begin at the 3rd digit from the back, advance 3 each time
   for (auto it = str.rbegin()+3; it < str.rend(); it += 3)
   {
      // this handles a negative sign (ignores it)
      if (isdigit(*it))
      {
         // there are currently no string functions dealing with reverse_iterators,
         // so use .base() to get it's corresponding forward_iterator

         // inserting into a string invalidates any iterators, so "reset" `it`, and
         // we have to make the return value into a reverse_iterator
         it = std::make_reverse_iterator(str.insert(it.base(), ','));
      }
   }
}

Note, there is some wariness using .base(), but all seems to be well for the inputs I tried. Above handles any length number string, with or without a preceding negative sign, but does not handle decimals. Also note that std::make_reverse_iterator requires c++14 or later.

Some sample inputs and outputs:

1 ==>                  1
12 ==>                 12
123 ==>                123
-12 ==>               -12
-123 ==>              -123
1234 ==>               1,234
-1234 ==>             -1,234
12134 ==>              12,134
-12134 ==>            -12,134
328947328949893 ==>    328,947,328,949,893
-328947328949893 ==>  -328,947,328,949,893
9328947328949893 ==>   9,328,947,328,949,893
-9328947328949893 ==> -9,328,947,328,949,893

Demonstration

ぺ禁宫浮华殁 2024-12-09 16:47:34

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

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

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文