长话短说:boost::locale
仅更改全局C++语言环境对象,但不更改C语言环境。 stod
使用C语言环境而不是全局C++语言环境对象。 std::locale
更改了全局C++语言环境对象和C语言环境。
原委:std::locale
是一种微妙的东西,并负责了很多调试!
让我们先从C++类的std ::区域设置:
std::locale loc("de_DE.utf8");
std::cout<<loc.name()<<"\n\n\n";
创建德语语言环境(如果可用你的机器上,否则它会抛出),这将导致在控制台上。
但它不会更改C++语言环境对象,该对象在程序启动时创建,并且是经典的(“C”),它不会更改全局 C++语言环境对象。的std::locale
不带参数的构造函数返回的全局状态的副本:
...
std::locale loc2;
std::cout<<loc2.name()<<"\n\n\n";
现在你应该看到C
如果没有之前搞砸了你的语言环境。std :: locale(“”)会做一些魔术,并找出用户的偏好并将其作为对象返回,而不是改变全局状态。在控制台上
std::locale::global(loc);
std::locale loc3;
std::cout<<loc3.name()<<"\n\n\n";
默认构造函数结果这次在:
您可以std::local::global
改变局部的状态。 我们可以通过调用恢复全局状态古典:
std::locale::global(std::locale::classic());
std::locale loc4;
std::cout<<loc4.name()<<"\n\n\n";
这应该给你再C
。
现在,当std :: cout被创建时,它会从全局C++状态克隆它的语言环境(这里我们用stringstreams来做,但它是一样的)。全局状态的后来的变化不影响数据流:
//classical formating
std::stringstream c_stream;
//german formating:
std::locale::global(std::locale("de_DE.utf8"));
std::stringstream de_stream;
//same global locale, different results:
c_stream<<1.1;
de_stream<<1.1;
std::cout<<c_stream.str()<<" vs. "<<de_stream.str()<<"\n";
给你1.1 vs. 1,1
- 首先是经典的第二个德国
您可以imbue(std::locale::classic())
改变流的本地语言环境的对象不言而喻不用说,这不会改变全局状态:
de_stream.imbue(std::locale::classic());
de_stream<<" vs. "<<1.1;
std::cout<<de_stream.str()<<"\n";
std::cout<<"global c++ state: "<<std::locale().name()<<"\n";
,你会看到:
1,1 vs. 1.1
global c++ state: de_DE.utf8
现在我们来到std::stod
。正如你可以想像它采用全球C++语言环境(并非完全如此,多多包涵)状态,而不是cout
-stream的(私人)状态:
std::cout<<std::stod("1.1")<<" vs. "<<std::stod("1,1")<<"\n";
给你1 vs. 1.1
因为全局状态仍"de_DE.utf8"
,所以第一个解析停在'.'
,但std::cout
的本地状态仍然是"C"
。恢复全局状态后,我们得到了经典行为:
std::locale::global(std::locale::classic());
std::cout<<std::stod("1.1")<<" vs. "<<std::stod("1,1")<<"\n";
现在德国"1,1"
不能正常解析:1.1 vs. 1
现在,你可能会认为,我们都做了,但还有更多 - 我答应告诉你约std::stod
。
除了全局C++语言环境,还有所谓的(全局)C语言环境(来自C语言,不要与经典的“C”语言环境混淆)。每次我们改变全局C++语言环境时,C语言环境也被改变了。
获取/设置C语言环境可以使用std::setlocale(...)
完成。查询当前值运行:
std::cout<<"(global) C locale is "<<std::setlocale(LC_ALL,NULL)<<"\n";
看(global) C locale is C
。要设置的C语言环境运行:
assert(std::setlocale(LC_ALL,"de_DE.utf8")!=NULL);
std::cout<<"(global) C locale is "<<std::setlocale(LC_ALL,NULL)<<"\n";
这产生(global) C locale is de_DE.utf8
。但是现在全球的C++语言环境是什么?
std::cout<<"global c++ state: "<<std::locale().name()<<"\n";
如您所料,C对C++全局语言环境一无所知,并保持不变:global c++ state: C
。
现在我们不再在堪萨斯了!旧的c函数将使用C语言环境和新的C++函数全局C++。鼓励自己进行有趣的调试!
,你会想到
std::cout<<"C: "<<std::stod("1.1")<<" vs. DE :"<<std::stod("1,1")<<"\n";
做什么? std::stod
毕竟是全新的C++ 11功能,它应该使用全局C++语言环境!再想想...:
1 vs. 1.1
它得到了德国格式正确,因为C语言环境被设置为“de_DE.utf8”,它的引擎盖下使用旧的C风格的函数。
只是为了完整起见,在std::streams
使用全局C++语言环境:
std::stringstream stream;//creating with global c++ locale
stream<<1.1;
std::cout<<"I'm still in 'C' format: "<<stream.str()<<"\n";
为您提供:I'm still in 'C' format: 1.1
。
编辑:的另一种方法来解析串没有与全局区域设置或搞乱通过它受到干扰:
bool s2d(const std::string &str, double &val, const std::locale &loc=std::locale::classic()){
std::stringstream ss(str);
ss.imbue(loc);
ss>>val;
return ss.eof() && //all characters interpreted
!ss.fail(); //nothing went wrong
}
以下测试表明:
double d=0;
std::cout<<"1,1 parsed with German locale successfully :"<<s2d("1,1", d, std::locale("de_DE.utf8"))<<"\n";
std::cout<<"value retrieved: "<<d<<"\n\n";
d=0;
std::cout<<"1,1 parsed with Classical locale successfully :"<<s2d("1,1", d, std::locale::classic())<<"\n";
std::cout<<"value retrieved: "<<d<<"\n\n";
d=0;
std::cout<<"1.1 parsed with German locale successfully :"<<s2d("1.1", d, std::locale("de_DE.utf8"))<<"\n";
std::cout<<"value retrieved: "<<d<<"\n\n";
d=0;
std::cout<<"1.1 parsed with Classical locale successfully :"<<s2d("1.1", d, std::locale::classic())<<"\n";
std::cout<<"value retrieved: "<<d<<"\n\n";
即仅在第一和最后的转换成功:
1,1 parsed with German locale successfully :1
value retrieved: 1.1
1,1 parsed with Classical locale successfully :0
value retrieved: 1
1.1 parsed with German locale successfully :0
value retrieved: 11
1.1 parsed with Classical locale successfully :1
value retrieved: 1.1
std :: stringstream可能不是最快的,但有其优点... ...
它会为您节省很多痛苦,长期来看,如果您要通过提供idx指针来检查解析错误std :: stod(str,** idx **) – ead
是的,我在我真实的代码中执行了这个操作,但为了这个简单的测试删除了它。 – NicolasR
好!我不知道这个项目有多大,但是改变全球的语言环境有可能在别的地方打破别的东西,但它应该是最后的选择......但是当你使用std :: stod时,你别无选择 – ead