C/C++程序中,locale(即系统区域设置,即国家或地区设置)将决定程序所使用的当前语言编码、日期格式、数字格式及其它与区域有关的设置,locale设置的正确与否将影响到程序中字符串处理(wchar_t如何输出、strftime()的格式等)。因此,对于每一个程序,都应该慎重处理locale设置。

C locale和C++ locale是独立的。C locale用setlocale(LC_CTYPE, “”)初始化,
C++ locale用std::locale::global(std::locale(“”))初始化。这样就可以根据当前运行环境正确设置locale。

根据环境变量中设置编码信息

使用第二个参数为”"的setlocale()调用会自动根据LC_ALL、LC_CTYPE和LANG环境变量的值设置合适的值。

  1. #include <locale.h>
  2. #include <locale>
  3. using std::locale;
  4. int main()
  5. {
  6. setlocale(LC_CTYPE, "");
  7. // 使用当前locale,但numpunct使用缺省的,因此不会在输出数字时加上千位分隔符
  8. locale::global(locale("").combine<std::numpunct<char> >(locale::classic()));setlocale()的有效的locale串
setlocale()的有效的locale串

在windows下可以用”.codepage”如”.936″来指定,linux下可以指定得更详细:”zh_CN.GB18030″。zh(语言,这里指中文)_CN(地区,这里指中国大陆).GB18030(该语言所使用的字符集)。可能有一个以上的国家/地区说某种特定的语言,例如,巴西和葡萄牙都说葡萄牙语。反之,一个国家/地区可能有一种以上的官方语言。例如,加拿大有两种官方语言:英语和法语。语言和地区两个因素组合才会确定一个字符集,即使用某个语言的某一地区会创建一个该地区的字符集来表示该语言的字符。

windows下不能直接指定“GB18030”,可能只能用“GBK”。

检测当前的语言环境是否使用了 UTF-8 编码
  • 先用setlocale()设置编码,再用nl_langinfo()进行检测

为检测当前语言环境是否使用了 UTF-8 编码。首先必须调用 setlocale(LC_CTYPE, “”) 函数,依据环境变量设置语言环境。nl_langinfo(CODESET) 函数也是由 locale charmap 命令调用,从而查找当前语言环境指定的编码名称。

  1. BOOL utf8_mode = FALSE;
  2. if(!strcmp(nl_langinfo(CODESET), "UTF-8")
  3. utf8_mode = TRUE;•直接查询环境变量
  4. 这项测试假设 UTF-8 语言环境名称中有值“UTF-8”,但实际情况并不总是如此,所以应该使用 nl_langinfo() 方法。
  5. char *s;
  6. BOOL utf8_mode = FALSE;
  7. if ((s = getenv("LC_ALL")) || (s = getenv("LC_CTYPE")) || (s = getenv ("LANG")))
  8. {
  9. if (strstr(s, "UTF-8"))
  10. utf8_mode = TRUE;
  11. }

附加:

区域设置(即locale)就成为语言、国家/地区和代码页的唯一组合。可以通过调用setlocale 函数在运行时更改区域设置和代码页设置。

参考:

locale C++  百度

C++之国际化(2) --- locale

分类: C++ 2014-03-03 13:30 487人阅读 评论(0) 收藏 举报

转载自:http://hi.baidu.com/nicker2010/item/8cc13bce77f11b3899b498eb

解决国际化问题,通常是通过locale环境,它被用来封装国家(地域)和文化之间的转换行为。
一个locale就是一个参数和函数的集合。根据X/Open公约,环境变量LANG用来确定当时的locale
不同的浮点数、日期、货币格式等则根据这个locale确定。

确定一个locale,需要采用以下字符串格式:
language[_area[.code]]
language表示语言,例如英语或者德语
_area表示该语言所处的地域、国家或者文化。用它可以在相同语言的不同国家之间实行转换
code定义字符编码方案,其重要性主要体现在亚洲,因为在那相同的字符集有不同的编码方案,如汉字的BIG5和GB
下面列出了典型的语言名称:

c           Default: ANSI-C conventions (English, 7 bit)
de_DE       German in Germany
de_DE.      88591   German in Germany with ISO Latin-1 encoding
de_AT       German in Austria
de_CH       German in Switzerland
en_US       English in the United States
en_GB       English in Great Britain
en_AU       English in Australia
en_CA       English in Canada
fr_FR       French in France
fr_CH       French in Switzerland
fr_CA       French in Canada
ja_JP.jis   Japanese in Japan with Japanese Industrial Standard (JIT) encoding
ja_JP.sjis  Japanese in Japan with Shift JIS encoding
ja_JP.ujis  Japanese in Japan with UNIXized JIS encoding
ja_JP.EUC   Japanese in Japan with Extended UNIX Code encoding
ko_KR       Korean in Korea
zh_CN       Chinese in China
zh_TW       Chinese in Taiwan
lt_LN.bit7  ISO Latin, 7 bit
lt_LN.bit8  ISO Latin, 8 bit
POSIX       POSIX conventions (English, 7 bit)

但它们尚未标准化。
对程序而言,这些名称是否标准化无关紧要,
因为locale的信息是由使用者根据以某种形式提供的。
普遍的做法是:程序只需读取环境变量或者类似的数据库,判断可用的locales,
然后便可以将“选择正确locale名称"的任务交给使用者。

C程序可以使用函数setlocale()来设定一个locale。
改变locale会对isupper()和toupper()之类的字符函数以及printf()之类的I/O函数产生影响
但C的解决方案有很多的限制。
C++的标准中,locale则被泛化,设计得更有弹性

locale使用示例:
cin.imbue(locale::classic()); ///使用经典的C的locale从标准流中读取数据
cout.imbue(local("de_DE")); ///imbue函数用来安装locale,///德国的小数点为逗号(',')
double value;
while(cin>>value)
    cout<<value<<endl;

其中cin.imbue(locale::classic());相当于cin.imbue(local("C"));

一般来说,除非需要读取某个固定格式来读取数据,否则程序不会预先定义一个特别的locale
而是会利用环境变量LANG来确定相应的locale
另外一种可能是读取一个locale名称然后利用之

示例代码:
locale langLocale(""); ///从环境变量LANG中读取缺省的locale对象
cout.imbue(langLocale);
bool isChina;
///locale.name()获取locale名称
if(langLocale.name() == "zh_CN" || langLocale.name() == "zh_TW")
    isChina = true;
else
    isChina = false;
if(isChina)
    cout<<"输入locale名称:"<<endl;
else
    cout<<"Input the name of locale:";
string locString;
cin>>locString;
if(!cin)
{
    if(isChina)
        cerr<<"读取数据时候发生错误!";
    else
        cerr<<"Error While reading";
    return;
}
local cinLocale(locString.c_str());

cin.imbue(cinLocale);
string value;
while(cin>>value)
    cout<<value<<endl;

locale类的静态函数global()可以用来安装一个全局的locale对象
这个对象可以用来作为某函数的locale对象参数的缺省参数
如果global()设定的locale对象是有名称的,则相当于C的locale调用了std::setlocale(LC_ALL,"")

不过,设定全局的locale对象,并不会替换已经存储于对象内部的locale。
它只能改变由缺省构造函数所产生的locale对象
例如下面的就是stream安装缺省的locale对象
cin.imbue(locale());
cout.imbue(locale());
cerr.imbue(locale());

下面是CodeBlocks中locale声明:

class locale
  {
  public:
    typedef int category;

class facet;
    class id;
    class _Impl;

friend class facet;
    friend class _Impl;

/**has_facet和use_facet是两个重要的友元函数

has_facet确定locale中是否有类型为_Facet的facet

use_facet返回locale中使用的类型为_Facet的facet对象的引用

*/

template<typename _Facet>
    friend bool has_facet(const locale&) throw();

template<typename _Facet>
    friend const _Facet& use_facet(const locale&);

template<typename _Cache> friend struct __use_cache;

/**locale中使用的facet*/

static const category none  = 0;
    static const category ctype  = 1L << 0;
    static const category numeric = 1L << 1;
    static const category collate = 1L << 2;
    static const category time  = 1L << 3;
    static const category monetary = 1L << 4;
    static const category messages = 1L << 5;
    static const category all  = (ctype | numeric | collate |
        time  | monetary | messages);

/**不同类型的构造函数以及析构*/
    locale() throw();
    locale(const locale& __other) throw();
    explicit locale(const char* __s); ///locale名为__s

//产生__base的一个副本,类型__cat中所有的facet将被__add的facet替换

locale(const locale& __base, const locale& __add, category __cat);

///相当于locale(__base, locale(__s),__cat);
    locale(const locale& __base, const char* __s, category __cat);

///产生__other的一个副本,并安装__f所指的facet

template<typename _Facet> locale(const locale& __other, _Facet* __f);
    ~locale() throw();

const locale& operator=(const locale& __other) throw();

///产生this的一个副本,并将__other中型别为_Facet的facet装入
    template<typename _Facet>locale combine(const locale& __other) const;
    string name() const; ///locale的名称字符串

/**比较函数*/
    bool operator==(const locale& __other) const throw ();
    inline bool operator!=(const locale& __other) const throw ()
    { return !(this->operator==(__other));  }

///operator()使得我们可以运用locale对象作为字符串比较工具,运用collate facet,(STL仿函数的行为)

////使用示例:vetor<string> vec;   std::sort(vec.begin(),vec.end(),locale("zh_CN"));
    template<typename _Char, typename _Traits, typename _Alloc>
    bool operator()(const basic_string<_Char, _Traits, _Alloc>& __s1,
                    const basic_string<_Char, _Traits, _Alloc>& __s2) const;

/**两个重要的成员函数global, classic

global将参数安装为全局的locale,并返回上一个全局locale

classic()返回locale("C")

*/
    static locale global(const locale&);
    static const locale& classic();

......

};

C++ 标准库的 locale 类用法

分类: 转帖好文 2011-01-04 23:22 6375人阅读 评论(1) 收藏 举报

目录(?)[+]

原来一篇总结了下 C 标准库的 setlocale() 用法,这篇讲解的是 C++ 标准库中 locale 类的用法。

参考:

locale 类在头文件 <locale> 中声明,另外可能会用到 <stdexcept> 中的标准异常类,和<iostream> 中的流对象类。

GNU libstdc++ 中的 locale

参考:

  1. locale 对象的构造

    构造函数有以下几个常用的重载形式:

    • locale()

      构造一个 locale 对象,它和程序当前的全局 locale 属性相同。

    • explicit locale(const char* _Locname)

      根据 locale 名构造一个 locale 对象,影响该对象的所有的 locale 类别(category),locale 名就是 C 标准库 setlocale() 中使用的名字,所以 libstdc++ 用的是 POSIX 标准的 locale 名,而 Windows CRT 实现的 locale 类,用的是 Windows 的 setlocale() 中特有的 locale 名字。

      和 setlocale() 类似,如果要使用环境设置的 locale 时,可以将 locale 名字写为空字符串""。

      注意这个构造函数被声明为显式的(explicit),说明隐式的参数转换会被认为是语法错误,例如:locale loc = "zh_CN.UTF-8" 会在编译时报错。

      当指定的 locale 名为 NULL,或是一个无效的名字,此构造函数会抛出 runtime_error 异常。

    • locale(const locale& _Loc, const locale& _Other, category _Cat)
      locale(const locale& _Loc, const char* _Locname, category _Cat)

      首先用 _Loc 拷贝构造一个 locale 对象作为基础 locale,然后从 _Other 或 _Locname 指定的 locale 中,抽取里面由 _Cat 指定的 category,替换掉基础 locale 中相应的 category。

      category 是 int 的 typedef,在 locale 类内有一些预定义的 category 常量(类静态常量成员),分别对应于 C 标准库中预定义的 locale 类别常量:

      locale::category 常量与 setlocale() 中的 category 参数对应关系
      locale::category 常量 setlocale() 中的 category
      all LC_ALL
      collate LC_COLLATE
      ctype LC_CTYPE
      messages LC_MESSAGES
      monetary LC_MONETARY
      none 表示所有 category 的空集(LC_ALL 的补集)
      numeric LC_NUMERIC
      time LC_TIME

      category 类型被用作掩码类型,所以上面 locale 类别可以用 | 进行组合,比如:monetary | time。

  2. locale 类静态方法

    • const locale& classic()

      得到一个表示 C locale 的 locale 对象。

    • locale global(const locale& _Loc)

      设置程序全局 locale 为 _Loc,返回以前的全局 locale。

      所谓全局 locale,就是流对象不用 imbue() 方法采用指定 locale 时的缺省 locale,相当于 C 标准库中 setlocale() 设定的 locale。程序初始化时,全局 locale 为 C locale。

      例如,设定全局 locale 为环境设置的 locale:

      1 // 相当于 setlocale(LC_ALL, "");
      2 locale::global(locale(""));
  3. locale 对象方法

    • string name() const

      返回 locale 的名字,例如,打印当前全局 locale 名字可以为:

      1 locale lc;
      2 cout << "Current global locale is: " << lc.name() << endl;

      注意:name() 返回的是 string 对象,而 wostream 的 << 操作在 string 上是无定义的,所以这个会出错:wcout << lc.name(),除非自己重载 wostream 的 << 操作。

  4. locale 使用示例与问题

    locale 类的作用和 setlocale() 相同:一是输出 wchar_t 字符时,根据活动 locale 将字符从 UCS 编码转换为 Native ANSI 编码,最后传递给终端、控制台设备;另一个作用是使用特定 locale 的某些 category 做操作(相应的函数、方法称为 locale 相关方法),比如:时间、货币文本的格式化,排序等等。

    使用 wcout 流对象和 locale 对象,输出 wchar_t 型字符限制很大,以下是正确向终端输出中文的例子:

    01 const wchar_t* strzh = L"中文abc";
    02  
    03 try
    04 {
    05     locale lc("zh_CN.UTF-8");
    06     locale::global(lc);
    07     // wcout.imbue(lc); // libstdc++ 的实现 imbue() 不起作用
    08     wcout << L"Zhong text is: " << strzh << endl;
    09 }
    10 catch (runtime_error& e)
    11 {
    12     cerr << "Error: " << e.what() << endl;
    13     cerr << "Type:" << typeid(e).name() << endl;
    14 }

    上面程序的运行环境为:终端和 shell 都使用 zh_CN.UTF-8 编码,最后用重定向输出到文件的方法测试出:输出的文本为 UTF-8 编码。

    限制来自于:无法混用 char 和 wchar_t 版的流对象,而很多对象只有返回 string 的方法(比如:locale::name()),导致必须使用 char 版的 cout、cerr 等,或者可以用 string::c_str() 方法。

    GNU libstdc++ 中实现的 locale 类,在使用时注意以下问题(VC8 中没有下面前两个问题):

    • 流对象的 imbue() 方法不起作用

      使用 locale::global() 设定全局 locale 后,wostream 可以输出正确转换的 Native ANSI 编码字符。而使用 wostream::imbue() 后,流对象无法向终端传递正确转换的编码字符。在测试 wcout 时,使用重定向输出到文件的方法发现:wcout 在输出含有 ASCII 外的 wchar_t 时,无法正确转换到 Native ANSI 编码字符,而转换成字节 0x3F(对应 ASCII 字符 ?)。

    • char 和 wchar_t 版的流对象不能混用

      和 glibc 实现的 C 标准库类似,在 libstdc++ 中混用 char 和 wchar_t 版的流对象,也会出现意外的错误,比如下面代码:

      01 const wchar_t* strzh = L"中文abc";
      02 locale lc("zh_CN.UTF-8");
      03 locale::global(lc);
      04  
      05 // 这句会引发后面的 wcout 输出错误
      06 cout << "abc" << endl;
      07  
      08 // 即使刷缓冲区和清空流对象状态也无法解决问题
      09 cout.flush();
      10 cout.clear();
      11 wcout.flush();
      12 wcout.clear();
      13  
      14 wcout << L"Zhong text is: " << strzh << endl;

      程序的输出如下:

      # ./test_03.exe | hd
      00000000 61 62 63 0a 5a 68 6f 6e 67 20 74 65 78 74 20 69 |abc.Zhong text i|
      00000010 73 3a 20 2d 87 61 62 63 0a |s: -.abc.|
      00000019

      上面程序错误之处为:没有将 "中文" 的 UCS-4 LE 编码 2D 4E 00 00 87 65 00 00 转换为正确的 UTF-8 编码 E4 B8 AD E6 96 87,而是将每个 wchar_t 字符的最低字节(L'中' 为 2D,L'文' 为 87)传给了终端。

      如果把 cout << "abc" << endl; 这句放到 wcout 之后,那么 wcout 是可以正常输出中文的,但 cout 就工作不正常了,根本就不向终端传递字符。

    • Cygwin 的 libstdc++ 中的 locale 实现

      测试版本:g++ 4.3.4,bash 3.2.49,cygwin1.dll 1.7.1,libstdc++6 4.3.4-3

      构造 locale 对象时,C.UTF-8,zh_CN.UTF-8,en_US.UTF-8 这些 locale 名字都无效,都会抛出runtime_error 异常,就连使用环境 locale 的空字符串参数 "" 都无效。只有一个 locale 名是有效的,就是最小的 C locale,即程序初始化时的默认locale。另外,Cygwin bash 启动后默认的 locale 为 C.UTF-8,可用查看 LANG 环境变量得知。

    • cout、wcout 与 printf()、wprintf() 的区别

      我的感觉是 cout、wcout 没有 printf()、wprintf() 好用,至少 printf()、wprintf() 都可以输出 wchar_t 型字符,而 cout 默认无法输出 wchar_t 型字符(当然可以自己重载 <<),而把 wchar_t 当整数输出,把 wchar_t[] 和 wchar_t* 输出个首地址。

      wostream 是可以以 char 型字符、字符串为 << 的参数的,但如果传入的 char 型字符在 ASCII 范围之外(在 0x00 ~ 0x7F 之外),wostream 是不会将正确的 Native ANSI 编码序列传递给终端、控制台设备的,导致终端中不会显示超出 ASCII 之外的字符。

      string 没有在 wostream 的 << 上定义,但可以用 string::c_str() 的方法让其输出 char 型字符,前提是事先知道 string 对象中不含有超出 ASCII 之外的字符。

Windows CRT 中的 locale

参考:

我在 VC8 下测试,和 GNU libstdc++ 的差异挺大,表现结果是:wcout.imbue(lc) 起作用,可以在控制台中输出含中文的 wchar_t 型字符,并且控制台得到的是根据 locale 转换的 Native ANSI 编码。Windows 的 locale 类实现不支持 UTF-8(代码页 65001),所以要用 GBK 的 locale,对应的 locale 名为 chs,长名字:Chinese_People's Republic of China.936。

用 VC8 的 locale::global(lc) 时有个奇怪的现象,它导致后面的 wcout 流输出到控制台完全没有显示,我将输出重定向到文件,发现结果正常,和用 imbue() 输出的相同,为 GBK 编码的中文。所以我认为,无法显示中文字符是 Windows 的控制台设备实现,以及 CRT 和控制台设备交互的问题,CRT 根据 locale 转换编码的工作是正常的。

另外,VC8 的 cout 和 wcout 的混用,以及 printf() 和 wprintf() 混用,都没有 GNU 实现的问题。

==================

https://blog.csdn.net/haiross/article/details/45074355

检测当前的语言环境是否使用了 UTF-8 编码(三篇文章:先用setlocale()设置编码,再用nl_langinfo()进行检测。locale对象可以使用langLocale.name() == "zh_CN"判断)的更多相关文章

  1. Python编程笔记(第三篇)【补充】三元运算、文件处理、检测文件编码、递归、斐波那契数列、名称空间、作用域、生成器

    一.三元运算 三元运算又称三目运算,是对简单的条件语句的简写,如: 简单条件处理: if 条件成立: val = 1 else: val = 2 改成三元运算 val = 1 if 条件成立 else ...

  2. 三篇文章带你极速入门php(二)之迅速搭建php环境

    前言 今天讲一下php在windows,mac,linux上的集成环境搭建,目标是简单快速,环境这个事得对号入座,windows用phpstudy,mac用mamp,linux用lnmp一键安装,直接 ...

  3. 如何正确设置 Informix GLS 及 CSDK 语言环境

    本文介绍 GLS 相关知识,说明如何正确设置 Informix GLS 语言环境相关变量(DB_LOCALE,CLIENT_LOCALE),保证 Informix 数据库服务器.客户端能正确的支持中文 ...

  4. 检测Windows程序的内存和资源泄漏之原生语言环境

    最近接连收到大客户的反馈,我们开发的一个软件,姑且称之为App-E吧,在项目规模特别大的情况下,长时间使用会逐渐耗尽内存,运行越来越缓慢,软件最终崩溃.由于App-E是使用混合语言开发的,主界面使用C ...

  5. 从小白到区块链工程师:第一阶段:Go语言环境的搭建(1)

    一,Golang语言简介 2009年由谷歌公司推出,由C语言之父Ken Thompson主导研发.Go(又称Golang)是Google开发的一种静态强类型.编译型.并发型,并具有垃圾回收功能的编程语 ...

  6. P4语言环境安装(一)前端编译器p4c、后端编译器p4c-bm2-ss

    这个P4安装环境是在2020-2-8安装的,安装环境卡了我好几天,把遇到的问题记录下来,有需要的同学可以参考一下,要是说错了或者有问题的话,评论或mail:guidoahead@163.com联系我都 ...

  7. 切换debian8系统语言环境

    想切换操作系统的默认语言环境,可以使用如下命令,而不用重新安装系统: 查看操作系统的语言: # env | grep LANG 使用root导入要使用的系统语言: # export LANG=en_U ...

  8. go语言环境搭建+sublime text3(windows环境下)

    感觉有点坑,整了一下午~搞定 go语言环境搭建+sublime text3(windows环境下) 1.安装sublime text3 2.安装go语言程序包 3.测试go语言是否安装成功     键 ...

  9. 转: KindEditor 图片空间文件增加删除文件、文件夹功能(ASP语言环境)

    KindEditor 图片上传功能中集成的图片空间文件管理插件可以对已上传图片进行管理,十分便捷,只是没有图片删除功能,仔细研读xieliang分享的经验后,自己动手改造了一下,顺便分享给有同样需求的 ...

随机推荐

  1. SSH——基于datagrid实现分页查询

    1. 修改页面中datagrid的URL地址,访问action // 取派员信息表格 $('#grid').datagrid( { iconCls : 'icon-forward', fit : tr ...

  2. android中的样式主题和国际化

    一.Android中的样式和主题     1.1样式     样式是作用在控件上的,它是一个包含一个或者多个view控件属性的集合.android style类似网页设计中的css设计思路,可以让设计 ...

  3. velcoity使用说明:foreach指令

    http://blog.csdn.net/madding/article/details/6641020当在velocity中需要显示一个列表信息,我们会用foreach循环输出, 要求: 假如现在需 ...

  4. GitExtensions工具安装与配置

    GitExtensions工具使用教程 第一步:安装 1.双击:GitExtensions24703SetupComplete.msi <ignore_js_op>  <ignore ...

  5. linux 系统下MySQL5.7重置root密码(完整版,含ERROR 1820 (HY000)解决方案)

    mysql的root密码忘记了怎么重置? 往下看: 1.保证你的mysql服务处于关闭状态.(用ps -ef | grep mysql 查看进程,有则kill -9 进程号) 2.在my.cnf所在目 ...

  6. library not found for -lPods-AFNetworking解决放案

    出现library not found for -lPods-AFNetworking这个报错, 来自于我从git上面把我项目直接Download下来的,我的项目里面用了CocoaPods的,如今pr ...

  7. FreeBSD编译安装emacs,不要用ports

    1. 解压emacs 2. 进入解压之后的目录,执行configure命令,大体配置如下: ./configure --with-x-toolkit=no --with-xpm=no --with-j ...

  8. Ubuntu17.10 Install Docker-ce

    官网目前的安装步骤在最新版本的Ubuntu17.10 上会提示没有安装源,下面是针对17.10 安装步骤: 参考资料 sudo apt-get update sudo apt-get install ...

  9. shell实现倒计时功能

    #!/bin/bash ############################################################## # File Name: oldboyedu.sh ...

  10. MAC下一些常用的命令行

    统计了一下工作中一些会常用到的简单命令,加强记忆 ls                       查看当前终端目录下面的文件 ls -a "ls -a"会出现一些带.xxxx的文 ...