某些特定 Windows 语言环境的奇怪行为:为啥以及如何应对?

Posted

技术标签:

【中文标题】某些特定 Windows 语言环境的奇怪行为:为啥以及如何应对?【英文标题】:Weird behaviour of some specific Windows locales: why, and how to cope?某些特定 Windows 语言环境的奇怪行为:为什么以及如何应对? 【发布时间】:2021-09-29 17:07:49 【问题描述】:

我编写了一个简单的 C++ 程序来测试可用的 Windows 语言环境。

#include <iostream>
#include <iomanip>
#include <locale>

int main(int argc, char* argv[])

    const char* locName = (argc < 2) ? "" : argv[1];

    std::locale loc (locName);
    std::cout.imbue(loc);

    std::cout << "Locale is " << loc.name() << '\n';
    std::cout << std::fixed << std::setprecision(8);
    std::cout << 12345654321 <<'\n';
    std::cout << 123456.54321 << '\n';;

    return 0;

我是用 msvc19 编译的。以下是一些测试结果:

c:\Temp>.\test
Locale is
12,345,654,321
123,456.54321000

c:\Temp>.\test C
Locale is C
12345654321
123456.54321000

到目前为止一切顺利。

c:\Temp>.\test xx_xx
Locale is xx_xx
12,345,654,321
123,456.54321000

c:\Temp>.\test xxx_xxx

c:\Temp>

区域设置xx_xx 不存在,xxx_xxx 也不存在,但是一个提供与默认区域设置相同的结果,另一个冻结流。好的,再做一些测试...

c:\Temp>.\test en_us
Locale is en_us
12,345,654,321
123,456.54321000

c:\Temp>.\test de_de
Locale is de_de
12.345.654.321
123.456,54321000

c:\Temp>

完美,应该如此。但是……

c:\Temp>.\test fr_fr
Locale is fr_fr
12345654321
c:\Temp>.\test fre_fr
Locale is fre_fr
12,345,654,321
123,456.54321000

c:\Temp>

什么? fr_fr 根本不会打印浮点数,但fre_fr 会(尽管,. 的角色显然颠倒了)。但是它们应该是同一语言环境的别名!

c:\Temp> python
>>> import locale
>>> locale.normalize('fr_fr')
'fr_FR.ISO8859-1'
>>> locale.normalize('fre_fr')
'fr_FR.ISO8859-1'

嗯……

c:\Temp>.\test fr_FR.ISO8859-1

c:\Temp>

根本没有输出。

现在我在某处读到不能使用编码后缀来设置 C 或 C++ 语言环境。我可以理解(尽管这很烦人)。但是为什么fr_fr(和frfrenchfr_FRFrench_France)的奇怪行为以及如何提前识别和避免这些有缺陷的语言环境?有趣的是,fr_befr_lu 的行为符合预期。

【问题讨论】:

documentation 的模式是 "&lt;language&gt;_&lt;country&gt;.&lt;code_page&gt;".utf8C 除外 我用fr_FR:12á345á654á321 123á456,54321000 得到这个输出——也许法语使用了一些非ASCII 字符作为千位分隔符,也许这会与控制台输出混淆,因为你的程序不是t 使用wchar_t 进行输出。尝试使用宽字符串输出函数,也许会更好。或者可能只是输出到一个字符串流并在可靠的调试器中查看它......或者一个文件...... 我期待 Locale is xx_xx 出现异常,请参阅 "...3,5) std::runtime_error 如果操作系统没有名为 std_name 的语言环境..." en.cppreference.com/w/cpp/locale/locale/locale @RichardCritten 确认MS has no documented deviation behavior on that @Mgetz MS 确认异常“..如果语言环境名称 locale_name 为空指针或其他无效,则函数抛出 runtime_error....” docs.microsoft.com/en-us/cpp/standard-library/…跨度> 【参考方案1】:

有两个不同的问题。

    就 Windows 而言,fre_frfr_FR.ISO8859-1 不是有效的区域设置名称。它们被某些第三方软件(Python 和可能其他软件)接受,但不能在 C setlocale 或 C++ std::locale 中使用它们。奇怪的是,当将无效的语言环境名称传递给 std::locale 构造函数时,似乎有两种不同的失败模式。有时它会像默认用户语言环境一样被无声地解释,有时会引发异常。 xx_xxfre_fr 属于第一类,xxx_xxxfr_FR.ISO8859-1 属于第二类。我对此没有任何解释。 fr_fr 使用非 ASCII 千位分隔符(不间断空格)。由于此语言环境使用的编码是 Latin-1,如果终端设置为处理 UTF-8,它将中断,因为此字符代码是不完整/无效的 UTF-8 序列。 chcp 1252 解决问题。

【讨论】:

以上是关于某些特定 Windows 语言环境的奇怪行为:为啥以及如何应对?的主要内容,如果未能解决你的问题,请参考以下文章

http:在主要方法中 - 为啥没有错误?奇怪的行为

为啥这个 for 循环在某些平台上退出而不在其他平台上退出?

奇怪的网站行为 - 具有特定值的 GET 参数导致网站重定向到 403

Powershell解压缩功能 - 奇怪的行为

为啥我的 C# 和 C++ dll 表现出不同的行为?

Python & Pandas:当 Pandas 将直方图绘制到特定轴时的奇怪行为