将 NUMBERFMT 与 GetNumberFormatEx 一起使用的正确方法是啥?

Posted

技术标签:

【中文标题】将 NUMBERFMT 与 GetNumberFormatEx 一起使用的正确方法是啥?【英文标题】:What's the proper way to use `NUMBERFMT` with `GetNumberFormatEx`?将 NUMBERFMT 与 GetNumberFormatEx 一起使用的正确方法是什么? 【发布时间】:2021-08-27 17:00:02 【问题描述】:

我正在为 Windows、Mac 和 Linux 编写一个区域感知节点应用程序。由于 javascript 对语言环境的处理没有考虑用户的自定义区域设置,因此我正在编写一个原生 Node 模块来为每个平台处理这个问题。

我正在设计一个函数,它需要一个数字来格式化和一个精度(小数点后的位数)并返回一个字符串。例如,如果我以 1 的精度传入 1234.456,并且我的区域设置使用“_”表示组,使用“/”表示小数,我希望使用用户当前语言和区域的适当区域设置信息“1_234/5”设置。

在 Windows 方面,我正在努力让 Windows API 准确地提供我想要的东西。这是我正在编写的 C++ 函数:

std::string FormatNumber(const double number, const int precision)

    std::wstringstream stream;
    stream.setf(std::ios::fixed, std::ios::floatfield);
    stream.precision(precision);
    stream << number;
    std::wstring roundedNumberStr = stream.str();
    const wchar_t *numStr = roundedNumberStr.c_str();

    wchar_t wBuffer[MAX_PATH];
    GetNumberFormatEx(
        LOCALE_NAME_USER_DEFAULT, // lpLocaleName,
        0,                        // dwFlags,
        numStr,                   // lpValue,
        NULL,                     // lpFormat,
        wBuffer,                  // lpNumberStr,
        MAX_PATH                  // cchNumber
    );

    // Return a std::string using wBuffer

这几乎可以完美运行,但无论我使用的精度如何(例如“1_234/00”),它总是精确到小数点后 2 位。为了解决这个问题,我怀疑我需要为lpFormat 传递一个参数。 Windows API 文档建议我只需要提供我想要控制的值并将其余的留给用户设置,所以我尝试了这样的事情:

    NUMBERFMTW format precision ;
    GetNumberFormatEx(
        LOCALE_NAME_USER_DEFAULT, // lpLocaleName,
        0,                        // dwFlags,
        numStr,                   // lpValue,
        &format,                  // lpFormat,
        wBuffer,                  // lpNumberStr,
        MAX_PATH                  // cchNumber
    );

但是...这会导致ERROR_INVALID_PARAMETER 错误。遗憾的是,文档并没有给我更多的见解。

那么如何让这个函数给我我期望的字符串呢?

【问题讨论】:

你需要更多的代码来设置format所有成员。 我要做的第一件事是初始化format: NUMBERFMTW format ; 有趣的是,当我将旧代码库切换到 VS2019 时,我现在在将 NUMBERFMT 结构初始化为 const 文字时收到 const 不兼容警告!看起来NUMBERFMT 的定义是LPWSTR 而不是LPCWSTR。我不太相信微软,这不仅仅是旧 C 时代的保留,不修改它......我将用 #pragma strict_gs_check(push, on)/#pragma strict_gs_check(pop) 指令包围该函数,以确保更加安全! 【参考方案1】:

完全初始化您的NUMBERFORMAT:

NUMBERFMTW formatNumDigits ;

您拥有的任何未初始化的成员都有未指定的(可能是随机的)值。

【讨论】:

感谢您的提示!我的 C++ 有点生疏了。不幸的是,这并不能消除错误。【参考方案2】:

NUMBERFMT 中的两个字符串不是可选的。其他成员是可选的,因为 0 是有效的,但 0 并不意味着它们获得正确的区域设置特定值!

使用LOCALE_SDECIMALLOCALE_STHOUSAND 调用GetLocaleInfoEx 以加载“正确”字符串,并使用LOCALE_SGROUPING 进行分组。 MSDN 会告诉您为其他成员使用哪个区域设置查询。

【讨论】:

以上是关于将 NUMBERFMT 与 GetNumberFormatEx 一起使用的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PhpSpreadSheet 中设置货币格式?

php [将产品与社交共享插件集成]将社交共享插件与WooCommerce集成 - Sharedaddy

php [将产品与社交共享插件集成]将社交共享插件与WooCommerce集成 - Sharedaddy

php [将产品与社交共享插件集成]将社交共享插件与WooCommerce集成 - Sharedaddy

php [将产品与社交共享插件集成]将社交共享插件与WooCommerce集成 - 分享此功能

php [将产品与社交共享插件集成]将社交共享插件与WooCommerce集成 - 分享此功能