如何使用C / C ++中的千位分隔符格式化数字

时间:2017-04-18 21:26:51

标签: c windows-mobile windows-ce pocketpc

我正在尝试做这个简单的任务。只是使用C或C ++格式化数字,但在Windows CE编程下。

在这种环境中,inbue和setlocale方法都不起作用。

最后我这样做没有成功:

char szValue[10];
sprintf(szValue, "%'8d", iValue);

有什么想法吗?

7 个答案:

答案 0 :(得分:1)

这是一种方法 - 创建自定义区域设置并使用适当自定义的方面填充它:

#include <locale>
#include <iostream>
#include <memory>

struct separate_thousands : std::numpunct<char> {
    char_type do_thousands_sep() const override { return ','; }  // separate with commas
    string_type do_grouping() const override { return "\3"; } // groups of 3 digit
};

int main()
{
    int number = 123'456'789;
    std::cout << "default locale: " << number << '\n';
    auto thousands = std::make_unique<separate_thousands>();
    std::cout.imbue(std::locale(std::cout.getloc(), thousands.release()));
    std::cout << "locale with modified thousands: " << number << '\n';
}

预期产出:

default locale: 123456789
locale with modified thousands: 123,456,789

答案 1 :(得分:1)

为什么要重新发明轮子而不使用为此提供的功能?请参阅GetNumberFormat

可以使用正确的NUMBERFMT结构值完成自定义格式设置。例如(伪代码):

//Display three digits after the decimal point.
.NumDigits = 3
//Display zeros after the decimal point.
.LeadingZero = 1
//Group every three digits to the left of the decimal.
.Grouping = 3
//Use a comma to as the decimal point (like they do in France and Spain).
.lpDecimalSep = ","
//Likewise, use a period as the grouping separator.
.lpThousandSep = "."
//Put the negative sign immediately after the number.
.NegativeOrder = 3

答案 2 :(得分:1)

我用这个:

string thousands_separator(long long k, string symbol=",") {
    int l, c, i;
    string fin, s, u, rev;
    bool min = false;
    fin = "";
    c = 0;
    if(k < -999){
        k *= -1;
        min = true;
    }
    s = to_string(k);
    if(k > 999){
        l = s.length() - 1;
        for (i = l; i >= 0; i--) {
            fin += s[i];
            c++;
            if(c%3 == 0){
                fin += symbol;
            }
        }
        rev = fin;
        fin = "";
        l = rev.length() - 1;
        for (i = l; i >= 0; i--) {
            fin += rev[i];
        }
        u = fin[0];
        if(u == symbol){
            fin.erase(fin.begin());
        }
        if(min){
            fin.insert(0, "-");
        }
        return fin;
    } else {
        return s;
    }
}

答案 3 :(得分:-1)

最后,我开发了自己的功能:

std::string CFormat::GetInteger(int iValue)
{
    std::string sValue;
    std::string sDot = ".";
    for(int iTmp = iValue; iTmp; iTmp /= 1000)
    {
        if ((int)(iTmp / 1000) == 0)
            sDot.clear();
        sValue = sDot + SSTR(iTmp % 1000) + sValue;
    }
    if (sValue.empty())
        sValue = "0";
    return sValue;
}

我认为它更简单,并且它不依赖于除std :: string之外的其他类,我知道它可以在Windows Mobile设备中使用。

答案 4 :(得分:-1)

这些函数在C ++中适用于字符串形式的数字(带或不带小数)。

下一个函数不支持负数或十进制分隔符,但是非常简单:

std::string quickAddThousandSeparators(std::string value, char thousandSep = ',')
{
    int len = value.length();
    int dlen = 3;

    while (len > dlen) {
        value.insert(len - dlen, 1, thousandSep);
        dlen += 4;
        len += 1;
    }
    return value;
}

下一个函数支持负数字符串和小数点分隔符:

std::string addThousandSeparators(std::string value, char thousandSep = ',', char decimalSep = '.', char sourceDecimalSep = '.')
{
    int len = value.length();
    int negative = ((len && value[0] == '-') ? 1: 0);
    int dpos = value.find_last_of(sourceDecimalSep);
    int dlen = 3 + (dpos == std::string::npos ? 0 : (len - dpos));

    if (dpos != std::string::npos && decimalSep != sourceDecimalSep) {
        value[dpos] = decimalSep;
    }

    while ((len - negative) > dlen) {
        value.insert(len - dlen, 1, thousandSep);
        dlen += 4;
        len += 1;
    }
    return value;
}

并且gtest通过了测试:

TEST (quickAddThousandSeparators, basicNumbers) {
    EXPECT_EQ("", quickAddThousandSeparators(""));
    EXPECT_EQ("1", quickAddThousandSeparators("1"));
    EXPECT_EQ("100", quickAddThousandSeparators("100"));
    EXPECT_EQ("1,000", quickAddThousandSeparators("1000"));
    EXPECT_EQ("10,000", quickAddThousandSeparators("10000"));
    EXPECT_EQ("100,000", quickAddThousandSeparators("100000"));
    EXPECT_EQ("1,000,000", quickAddThousandSeparators("1000000"));
    EXPECT_EQ("1,000,000,000", quickAddThousandSeparators("1000000000"));
    EXPECT_EQ("1,012,789,345,456,123,678,456,345,809", quickAddThousandSeparators("1012789345456123678456345809"));
}

TEST (quickAddThousandSeparators, changeThousandSeparator) {
    EXPECT_EQ("", quickAddThousandSeparators("",'.'));
    EXPECT_EQ("1", quickAddThousandSeparators("1",'.'));
    EXPECT_EQ("100", quickAddThousandSeparators("100", '.'));
    EXPECT_EQ("1.000", quickAddThousandSeparators("1000", '.'));
    EXPECT_EQ("1.000.000.000", quickAddThousandSeparators("1000000000", '.'));
    EXPECT_EQ("1.012.789.345.456.123.678.456.345.809", quickAddThousandSeparators("1012789345456123678456345809", '.'));
}

TEST (addThousandSeparators, basicNumbers) {
    EXPECT_EQ("", addThousandSeparators(""));
    EXPECT_EQ("1", addThousandSeparators("1"));
    EXPECT_EQ("100", addThousandSeparators("100"));
    EXPECT_EQ("1,000", addThousandSeparators("1000"));
    EXPECT_EQ("10,000", addThousandSeparators("10000"));
    EXPECT_EQ("100,000", addThousandSeparators("100000"));
    EXPECT_EQ("1,000,000", addThousandSeparators("1000000"));
    EXPECT_EQ("1,000,000,000", addThousandSeparators("1000000000"));
    EXPECT_EQ("1,012,789,345,456,123,678,456,345,809", addThousandSeparators("1012789345456123678456345809"));
}

TEST (addThousandSeparators, negativeBasicNumbers) {
    EXPECT_EQ("", addThousandSeparators(""));
    EXPECT_EQ("-1", addThousandSeparators("-1"));
    EXPECT_EQ("-100", addThousandSeparators("-100"));
    EXPECT_EQ("-1,000", addThousandSeparators("-1000"));
    EXPECT_EQ("-10,000", addThousandSeparators("-10000"));
    EXPECT_EQ("-100,000", addThousandSeparators("-100000"));
    EXPECT_EQ("-1,000,000", addThousandSeparators("-1000000"));
    EXPECT_EQ("-1,000,000,000", addThousandSeparators("-1000000000"));
    EXPECT_EQ("-1,012,789,345,456,123,678,456,345,809", addThousandSeparators("-1012789345456123678456345809"));
}

TEST (addThousandSeparators, changeThousandSeparator) {
    EXPECT_EQ("", addThousandSeparators("",'.'));
    EXPECT_EQ("-1", addThousandSeparators("-1",'.'));
    EXPECT_EQ("100", addThousandSeparators("100", '.'));
    EXPECT_EQ("-1.000", addThousandSeparators("-1000", '.'));
    EXPECT_EQ("-1.000.000.000", addThousandSeparators("-1000000000", '.'));
    EXPECT_EQ("1.012.789.345.456.123.678.456.345.809", addThousandSeparators("1012789345456123678456345809", '.'));
}

TEST (addThousandSeparators, changeDecimalSeparator) {
    EXPECT_EQ("0,5", addThousandSeparators("0.5",'.',','));
    EXPECT_EQ("0", addThousandSeparators("0",'.',','));
    EXPECT_EQ("-1,23", addThousandSeparators("-1.23",'.',','));
    EXPECT_EQ("100,56", addThousandSeparators("100.56", '.',','));
    EXPECT_EQ("-1.000,786", addThousandSeparators("-1000.786", '.',','));
    EXPECT_EQ("-1.000.000.000,4859", addThousandSeparators("-1000000000.4859", '.', ','));
    EXPECT_EQ("1.012.789.345.456.123.678.456.345.809,6785960", addThousandSeparators("1012789345456123678456345809.6785960", '.',','));
}

TEST (addThousandSeparators, changeSourceDecimalSeparator) {
    EXPECT_EQ("0,5", addThousandSeparators("0,5",'.',',',','));
    EXPECT_EQ("0", addThousandSeparators("0",'.',',',','));
    EXPECT_EQ("-1,23", addThousandSeparators("-1,23",'.',',',','));
    EXPECT_EQ("100,56", addThousandSeparators("100,56", '.',',',','));
    EXPECT_EQ("-1.000,786", addThousandSeparators("-1000,786", '.',',',','));
    EXPECT_EQ("-1.000.000.000,4859", addThousandSeparators("-1000000000,4859", '.', ',',','));
    EXPECT_EQ("1.012.789.345.456.123.678.456.345.809,6785960", addThousandSeparators("1012789345456123678456345809,6785960", '.',',',','));
}

答案 5 :(得分:-2)

这是另一种方式,使用手动操作:

#include <iostream>
#include <string>
#include <algorithm>

int main()
{
    int number = 123'456'789;
    auto src = std::to_string(number);
    auto dest = std::string();

    auto count = 3;
    for(auto i = src.crbegin() ; i != src.crend() ; ++i) {
        if (count == 0)
        {
            dest.push_back(',');
            count = 3;
        }
        if (count--) {
            dest.push_back(*i);
        }
    }
    std::reverse(dest.begin(), dest.end());

    std::cout << dest << '\n';
}

答案 6 :(得分:-2)

注意:在提交此答案时,帖子被标记为C / C ++。现在它被标记为C.我怀疑它可能会再次发生变化。

如果您想要推出使用C99的自己的C解决方案,下面将构成在各种区域设置下在我的Windows gcc上运行的基础。

#include <locale.h>
#include <stdio.h>
#include <stdlib.h>

#define INT_STR_SIZE (CHAR_BIT*sizeof(int)*3/10 + 2)
#define INT_SEP_STR_SIZE (INT_STR_SIZE * 3/2 + 1)
#define INT_SEP(x) int_sep((char[INT_SEP_STR_SIZE]) { "" }, INT_SEP_STR_SIZE, x)

char *int_sep(char *s, size_t sz, int x) {
  struct lconv *locale_ptr = localeconv();
  const char *grouping = locale_ptr->grouping;
  char sep = locale_ptr->thousands_sep[0];

  if (sz > 0) {
    int x0 = x;
    char *ptr = s + sz;
    *--ptr = '\0';
    char count = 0;
    do {
      if (count >= grouping[0]) {
        *--ptr = sep;
        if (grouping[1]) grouping++;
        count = 0;
      }
      count++;
      //printf("%d %d <%s> %p\n", count, n, locale_ptr->grouping, (void*)locale_ptr);
      *--ptr = (char) (abs(x % 10) + '0');
    } while (x /= 10);
    if (x0 < 0) {
      *--ptr = '-';
    }
    memmove(s, ptr, (size_t) (&s[sz] - ptr));
  }
  return s;
}

int main(void) {
  puts(setlocale(LC_ALL,"en_US"));
  printf(":%15s: :%15s: :%15s:\n", INT_SEP(INT_SEP_STR_SIZE), INT_SEP(12345678), INT_SEP(1234));
  printf(":%15s: :%15s: :%15s:\n", INT_SEP(-1), INT_SEP(0), INT_SEP(1));
  printf(":%15s: :%15s: :%15s:\n", INT_SEP(INT_MIN), INT_SEP(INT_MIN+1), INT_SEP(INT_MAX));
  puts(setlocale(LC_ALL,"C"));
  printf(":%15s: :%15s: :%15s:\n", INT_SEP(INT_MIN), INT_SEP(INT_MIN+1), INT_SEP(INT_MAX));
  puts(setlocale(LC_ALL,"it_IT"));
  printf(":%15s: :%15s: :%15s:\n", INT_SEP(INT_MIN), INT_SEP(INT_MIN+1), INT_SEP(INT_MAX));
  puts(setlocale(LC_ALL,"as_IN"));
  printf(":%15s: :%15s: :%15s:\n", INT_SEP(INT_MIN), INT_SEP(INT_MIN+1), INT_SEP(INT_MAX));
  puts(setlocale(LC_ALL,"be_BY"));
  printf(":%15s: :%15s: :%15s:\n", INT_SEP(INT_MIN), INT_SEP(INT_MIN+1), INT_SEP(INT_MAX));
  return 0;
}

输出

en_US
:             17: :     12,345,678: :          1,234:
:             -1: :              0: :              1:
: -2,147,483,648: : -2,147,483,647: :  2,147,483,647:
C
:    -2147483648: :    -2147483647: :     2147483647:
it_IT
: -2.147.483.648: : -2.147.483.647: :  2.147.483.647:
as_IN
:-2,14,74,83,648: :-2,14,74,83,647: : 2,14,74,83,647:
be_BY
: -2 147 483 648: : -2 147 483 647: :  2 147 483 647: