C++国际化(各种乱码的解决方案之一)

来源:互联网 发布:gave算法中是什么意思 编辑:程序博客网 时间:2024/05/19 21:43

C++之国际化(1)

    国际化(Internationalization,简写为i18n)
    国际化的主要思路是以locale(地域、本土、国别)对象来代表一个可扩展的面貌集合, 以此进行地区转换工作。

    Locale在C中已经有所应用,
    但在C++的标准中,locale被泛化,设计得更有弹性。

    事实上,C++ locale机制可以根据用户环境或者偏好进行定制,
    例如可以对它进行扩展,使他能够处理时区、纸张规格等问题

    C++ stream进行I/O时,所有的数值会更加locale规定的规则自动进行格式化
    程序员也可以使用locale对象进行直接格式化、校勘(collation)、字符分类等工作。

    string和stream中使用了char_traits
    template<typename _CharT>
    struct char_traits
    {
      typedef _CharT                                    char_type;
      typedef typename _Char_types<_CharT>::int_type    int_type;
      typedef typename _Char_types<_CharT>::pos_type    pos_type;
      typedef typename _Char_types<_CharT>::off_type    off_type;
      typedef typename _Char_types<_CharT>::state_type  state_type;

      static void assign(char_type& __c1, const char_type& __c2)
      { __c1 = __c2; }

      static bool eq(const char_type& __c1, const char_type& __c2)
      { return __c1 == __c2; }

      static bool lt(const char_type& __c1, const char_type& __c2)
      { return __c1 < __c2; }

      static int compare(const char_type* __s1, const char_type* __s2, std::size_t __n)
      {  for (size_t __i = 0; __i < __n; ++__i)
            if (lt(__s1[__i], __s2[__i]))
                return -1;
            else if (lt(__s2[__i], __s1[__i]))
                return 1;
         return 0;
      }

      static std::size_t length(const char_type* __s)
      { std::size_t __i = 0;
        while (!eq(__p[__i], char_type()))
            ++__i;
        return __i;
      }

      static const char_type* find(const char_type* __s, std::size_t __n, const char_type& __a)
      { for (std::size_t __i = 0; __i < __n; ++__i)
            if (eq(__s[__i], __a))
            return __s + __i;
        return 0;
      }

      static char_type* move(char_type* __s1, const char_type* __s2, std::size_t __n)
      {return static_cast<_CharT*>(std::memmove(__s1, __s2,
            __n * sizeof(char_type)));
      }

      static char_type* copy(char_type* __s1, const char_type* __s2, std::size_t __n)
      { std::copy(__s2, __s2 + __n, __s1);
        return __s1;
      }

      static char_type* assign(char_type* __s, std::size_t __n, char_type __a)
      { std::fill_n(__s, __n, __a);
        return __s;
      }

      static char_type to_char_type(const int_type& __c)
      { return static_cast<char_type>(__c); }

      static int_type to_int_type(const char_type& __c)
      { return static_cast<int_type>(__c); }

      static bool eq_int_type(const int_type& __c1, const int_type& __c2)
      { return __c1 == __c2; }

      static int_type eof()
      { return static_cast<int_type>(EOF); }

      static int_type not_eof(const int_type& __c)
      { return !eq_int_type(__c, eof()) ? __c : to_int_type(char_type()); }
    };

    处理特殊字符:
    如换行符('\n')、EOF等
    类basic_ios提供了成员函数widen(),narrow()来处理这个问题
    如:
    strm.widen('\n');
    strm.widen('\0');
    函数widen(),narrow()实际上使用了一个locale对象,更确切的说是该对象的ctype facet
    ,这个facet用来对所有字符"在char和其他表现形式之间"进行转换.

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

解决国际化问题,通常是通过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();

......

};


原创粉丝点击