一些特定的Windows语言环境的奇怪行为:为什么,以及如何应对?



我写了一个简单的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的行为与预期一致。

有两个独立的问题。

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

相关内容

  • 没有找到相关文章

最新更新