如何在数字中使用空格作为千位分隔符打印数字?

8

我有一个简单的Currency类,其中包含重载的operator<<。我不知道如何在每三个数字之间分隔数字,使其看起来像这样:"1 234 567 ISK"。

#include <cstdlib>
#include <iostream>

using namespace std;

class Currency
{
    int val;
    char curr[4];

    public:
    Currency(int _val, const char * _curr)
    {
        val = _val;
        strcpy(curr, _curr);
    }

    friend ostream & operator<< (ostream & out, const Currency & c);
};

ostream & operator<< (ostream & out, const Currency & c)
{
    out << c.val<< " " << c.curr;
    return out;
}

int main(int argc, char *argv[])
{
    Currency c(2354123, "ISK");
    cout << c;
}

我感兴趣的是,对于这种特定情况,最简单的解决方案。


1
@danben:将其标记为[作业]会改变问题或如何评判好答案的方式吗? - Roger Pate
2
@Roger Pate:将一个问题标记为作业可以让SO社区知道他们应该给予指导,帮助发帖者自己找到解决方案,而不是直接为他写出解决方案。请参见http://meta.stackexchange.com/questions/10811/how-to-ask-and-answer-homework-questions。 - danben
@danben:请参考http://meta.stackexchange.com/questions/10811/how-to-ask-and-answer-homework-questions/10825#10825和http://meta.stackexchange.com/questions/10811/how-to-ask-and-answer-homework-questions/10839#10839。 - Roger Pate
@Roger Pate - 请注意,这些链接是指得分相对较低的答案。任何人都可以为任何问题添加任何答案,但考虑到SO政策是由社区管理的,您确实希望给最高投票的答案赋予最大的权重。还要注意,Joel在那篇顶级文章中所做的是概述了最能调和大多数意见的政策,并且它被认为是最高投票的答案,因此应该是有效的。 - danben
@danben:Joel 也说过:“其他观点不必在投票中击败这个观点才能产生影响。如果你考虑到我无意中创造的群体思维,他们非常接近成功。” - Roger Pate
4个回答

15

这可以通过使用“facets”来实现。

struct myseps : numpunct<char> { 
   /* use space as separator */
   char do_thousands_sep() const { return ' '; } 

   /* digits are grouped by 3 digits each */
   string do_grouping() const { return "\3"; }
};

int main() {
  std::cout.imbue(std::locale(std::locale(), new myseps));
  std::cout << 10000; // 10 000
}

或者,你可以编写自己的循环

void printGrouped(ostream &out, int n) {
  if(n < 0) {
    out << "-";
    return printGrouped(out, -n);
  }

  if(n < 1000) {
    out << n;
  } else {
    printGrouped(out, n / 1000);
    out << " " << setw(3) << setfill('0') << (n % 1000);
  }
}

ostream & operator<< (ostream & out, const Currency & c) {
    printGrouped(out, c.val);
    out << " " << c.curr;
    return out;
}

虽然几乎肯定不希望更改如何打印所有数字。 - Roger Pate
locale("") 是实现定义的。在OS X 10.5上它不起作用(抛出runtime_exception,带有what() "locale :: facet::_S_create_c_locale name not valid")。相反,您可以使用默认构造函数来使用当前全局语言环境。 - wilhelmtell
2
@wilhelmtell 我故意使用了 locale(""),因为根据 Stroustrup 在 TC++PL 的语言环境附录中所述,它使用的是“用户首选语言环境”,而 C++ 标准规定有效参数包括 "C" 和 ""(我猜测 "" 应该使用一些环境变量?)。暂时更改为默认构造函数。有人知道在 OSX 上发生了什么导致它不起作用吗? - Johannes Schaub - litb
感谢您提供有关除以/取模1000的明确而好的提示。这正是我正在寻找的。 - Krzysztof Szynter

7

可能的一种方法是使用语言环境来实现此功能。

#include <locale>
#include <string>
#include <cstddef>

class SpaceSeparator: public std::numpunct<char>
{
public:
    SpaceSeparator(std::size_t refs): std::numpunct<char>(refs) {}
protected:
    char do_thousands_sep() const { return ' '; }
    std::string do_grouping() const { return "\03"; }
};

//...    
ostream & operator<< (ostream & out, const Currency & c)
{
    SpaceSeparator facet(1); //1 - don't delete when done
    std::locale prev = out.imbue(std::locale(std::locale(), &facet));
    out << c.val<< " " << c.curr;
    out.imbue(prev);  //restore previous locale
    return out;
}

1
然而,std::moneypunct将是更好的facet来使用。 - Roger Pate

2
struct Currency {
  static char const sep = ' ';
  static int const group_size = 3;

  Currency(int val, std::string unit)
  : val(val), unit(unit)
  {}

  friend std::ostream& operator<<(std::ostream& out, Currency const& v) {
    // currently ignores stream width and fill
    std::ostringstream ss;
    bool const neg = v.val < 0;
    int const val = (neg ? -v.val : v.val);
    if (neg) out << '-';
    ss << val;
    std::string const s = ss.str();
    std::string::size_type n = s.size() % v.group_size;
    if (n) out << s.substr(0, n);
    for (; n < s.size(); n += v.group_size) {
      out << sep << s.substr(n, v.group_size);
    }
    out << ' ' << v.unit;
    return out;
  }

private:
  int val;
  std::string unit;
};

如果您想自定义每个对象的逗号等内容,可以将sep和group_size设置为非静态成员变量。 (如果是这样,请将它们设为私有并在构造函数中初始化,可能使用默认参数值。)您还可以使用控制输出格式的traits类。

本地化还通过moneypunct facet支持货币格式化。


-1
#include <iostream>

#include <sstream>

#include <cstdlib>

#define GROUP_SEP ','

#define GROUP_SIZE 3

using namespace std;

string  output_formatted_string(long long num);


int main() { 

    string temp;

    cout << "Enter a large number:  ";

    getline(cin, temp);

    long long num = atoll(temp.c_str());

    string output = output_formatted_string(num);


    cout << output << endl;

    return 0;

    }

    string output_formatted_string(long long num)

    { 

    stringstream temp, out;

    temp << num;

    string s = temp.str();


    int n = s.size() % GROUP_SIZE;

    int i = 0;

    if(n>0 && s.size() > GROUP_SIZE)

      {

        out << s.substr(i, n) << GROUP_SEP;

        i += n;

      }


    n = s.size() / GROUP_SIZE - 1;

    while(n-- > 0)
         {

        out << s.substr(i, GROUP_SIZE) << GROUP_SEP;

        i += GROUP_SIZE;         
}

    out << s.substr(i);

    return out.str();

    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接