使用默认值填充NUMBERFMT的简便方法是什么?

时间:2011-08-27 12:51:20

标签: winapi localization

我正在使用Windows API GetNumberFormatEx格式化某些数字以显示当前用户的相应本地化选项(例如,确保它们在正确的位置具有正确的分隔符)。当您想要完全符合用户默认值时,这是微不足道的。

但在某些情况下,我有时必须覆盖基数分隔符后面的位数。这需要提供NUMBERFMT结构。我想要做的是调用一个API,返回为用户填充适当默认值的NUMBERFMT,然后只覆盖我需要更改的字段。但似乎没有API来获取默认值。

目前,我一遍又一遍地调用GetLocaleInfoEx,然后将该数据转换为NUMBERFMT所需的格式。

NUMBERFMT fmt = {0};
::GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT,
                  LOCALE_IDIGITS | LOCALE_RETURN_NUMBER,
                  reinterpret_cast<LPWSTR>(&fmt.NumDigits),
                  sizeof(fmt.NumDigits)/sizeof(WCHAR));
::GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT,
                  LOCALE_ILZERO | LOCALE_RETURN_NUMBER,
                  reinterpret_cast<LPWSTR>(&fmt.LeadingZero),
                  sizeof(fmt.LeadingZero)/sizeof(WCHAR));
WCHAR szGrouping[32] = L"";
::GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SGROUPING, szGrouping,
                  ARRAYSIZE(szGrouping));
if (::lstrcmp(szGrouping, L"3;0") == 0 ||
    ::lstrcmp(szGrouping, L"3") == 0
) {
    fmt.Grouping = 3;
} else if (::lstrcmp(szGrouping, L"3;2;0") == 0) {
    fmt.Grouping = 32;
} else {
    assert(false);  // unexpected grouping string
}
WCHAR szDecimal[16] = L"";
::GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SDECIMAL, szDecimal,
                  ARRAYSIZE(szDecimal));
fmt.lpDecimalSep = szDecimal;
WCHAR szThousand[16] = L"";
::GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_STHOUSAND, szThousand,
                  ARRAYSIZE(szThousand));
fmt.lpThousandSep = szThousand;
::GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT,
                  LOCALE_INEGNUMBER | LOCALE_RETURN_NUMBER,
                  reinterpret_cast<LPWSTR>(&fmt.NegativeOrder),
                  sizeof(fmt.NegativeOrder)/sizeof(WCHAR));

是否有API已经执行此操作?

2 个答案:

答案 0 :(得分:2)

我上周刚写了一些代码来做这件事。唉,似乎没有GetDefaultNumberFormat(LCID lcid,NUMBERFMT * fmt)函数;你必须自己编写,因为你已经开始了。另外,分组字符串具有明确定义的格式,可以轻松解析;你的当前代码对于“3”(应该是30)是错误的,并且显然会在更多异国情调的分组上失败(尽管这可能不是很关心,真的)。

答案 1 :(得分:0)

如果您要做的只是剪切字符串末尾的小数位,您可以使用其中一种默认格式(如LOCALE_NAME_USER_DEFAULT),然后检查是否存在小数分隔符(在生成的字符串中使用大陆语言中的逗号(以英语表示),然后通过将其替换为空字节来删除小数部分:

#define cut_off_decimals(sz, cch) \
    if (cch >= 5 && (sz[cch-4] == _T('.') || sz[cch-4] == _T(','))) \
        sz[cch-4] = _T('\0');

(匈牙利警报:sz是C字符串,cch是字符数,包括终止空字节。_Tchar的Windows通用文本makro }或wchar_t取决于是否定义了UNICODE,仅在与Windows 9x / ME兼容时才需要。)

请注意,对于用户定义格式的非常奇怪的情况,这会产生错误的结果,其中倒数第三个字符是点或逗号,对用户有一些特殊含义小数分隔符以外的内容。我一生中从未见过如此数字的格式,因此我得出结论认为这是好的和安全的。

当然,如果第三个到最后一个字符既不是点也不是逗号,这将不起作用。

相关问题