c ++:用逗号格式化数字?


73

我想编写一个方法,该方法将接受一个整数并返回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用逗号将数字格式化为a的C ++方法是什么?

(奖金也将处理double。)




1
这些重复语句的statements脚之处在于,我在使用最明显的搜索词之前搜索了此问题,但没有找到任何一个问题。我的头衔更好,而且更切题,而且我喜欢我的问题的答案胜于任何一个答案。
用户

如果高性能是一个问题,您可以看到我的相关问题:如何使用逗号来改善格式编号?
用户

Answers:


57

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

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


@罗伯·肯尼迪(Rob Kennedy):stackoverflow.com/questions/4406895/…–
雅各布(Jacob)

3
此功能对我来说没有逗号。我应该设置什么语言环境?我应该要求用户设置哪个语言环境?失败。
强尼

没有使用特定语言环境的示例,答案是不完整的。要使其正常工作,需要学习整个语言环境机器。
Reb.Cabin's

更具体地说,答案确实否认可移植性是个问题,您应该查看传递“”时使用的语言环境。事实证明,此答案无法在Mac上即用即用,但是“查看所使用的语言环境”需要沿语言区域进入“兔子洞”。请参阅以下问题以获取开箱即用的更好答案:stackoverflow.com/questions/3479485
Reb.Cabin 2015年

53

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

只是好奇是否可以长时间编辑示例而不是float,因为这就是我要搜索的(这就是问题的所在。)
Fellow Traveler

1
@FellowTraveler一样,只是做std::cout << myLongValue;
节点

为什么即使没有管道std :: fixed也能长时间工作呢?(没有尝试双打)。
2014年

这很棒!现在无需弄乱UTF-8语言环境!
ForceBru

到目前为止,最好的方法之一是
Vivick '17

35

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

#include <iostream>
int main() {
   auto s = std::to_string(7654321);
   int n = s.length() - 3;
   while (n > 0) {
      s.insert(n, ",");
      n -= 3;
   }
   std::cout << (s == "7,654,321") << std::endl;
}   

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


这不适用于前缀为零的值,例如010100
PapaDiHatti

@ Homer6负数的问题可以通过对代码进行较小的调整来解决。如果该数字为负数,则while循环条件应为insertPosition> 1 ... -106的insertPosition将从1开始并且不插入逗号。
卡迪夫太空人

@Kapil数字以0开头,例如010100可以工作:您将得到insertPosition == 3开始,您的逗号将介于3位数和4位数之间,仅此而已。您能否进一步说明这样的数字字符串将如何失败?
卡迪夫太空人

@arljalal我非常喜欢代码。在我看来,唯一的缺陷是,如果真的很长的数字很常见,那就是O(长度平方)。while循环运行O(length)次,每次传输O(length)个数字。在逗号分隔的块上运行的算法总体上可能为O(长度)。我们大多数人将格式化32位或64位数字,因此问题很小。
卡迪夫太空人

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

我喜欢这样(除了运算符之间没有空格)。尽管在较新的处理器上,除以1,000的速度可能很快,但是您可以在堆栈上分配一个缓冲区,并反向生成数字并打印每个字符,每3个字符还输出一个逗号...
Alexis Wilke,

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

这会调用未定义的行为(在我的测试中为双重释放或损坏),因为您正在传递指向的指针,该指针未由分配newnew如在其他答案中那样使用,或在构面的构造函数中将基类refcount设置为1!
Cubbi 2013年

感谢您指出。我仅在可以正常工作的iOS上对其进行了测试。它不适用于Mac。
Radif Sharafullin

1

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

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

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


-1

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

#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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.