5.2. 区域设置

在进入正题之前,有必要先审视下区域设置的问题,本章中提到的很多函数都需要一个附加的区域设置参数。

区域设置在标准 C++ 中封装了文化习俗相关的内容,包括货币符号,日期时间格式, 分隔整数部分与分数部分的符号(基数符)以及多于三个数字时的分隔符(千位符)。

在字符串处理方面,区域设置和特定文化中对字符次序以及特殊字符的描述有关。 例如,字母表中是否含有变异元音字母以及其在字母表中的位置都由语言文化决定。

如果一个函数用于将字符串转换为大写形式,那么其实施步骤取决于具体的区域设置。 在德语中,字母 'ä' 显然要转换为 'Ä', 然而在其他语言中并不一定。

使用类 std::string 时区域设置可以忽略, 因为它的函数均不依赖于特定语言。 然而在本章中为了使用 Boost C++ 库, 区域设置的知识是必不可少的。

C++ 标准中在 locale 文件中定义了类 std::locale 。 每个 C++ 程序自动拥有一个此类的实例, 即不能直接访问的全局区域设置。 如果要访问它,需要使用默认构造函数构造类 std::locale 的对象,并使用与全局区域设置相同的属性初始化。

  1. #include <locale>
  2. #include <iostream>
  3.  
  4. int main()
  5. {
  6. std::locale loc;
  7. std::cout << loc.name() << std::endl;
  8. }

以上程序在标准输出流输出 C ,这是基本区域设置的名称,它包括了 C 语言编写的程序中默认使用的描述。

这也是每个 C++ 应用的默认全局区域设置,它包括了美式文化中使用的描述。 例如,货币符号使用美元符号,基字符为英文句号,日期中的月份用英语书写。

全局区域设置可以使用类 std::locale 中的静态函数 global() 改变。

  1. #include <locale>
  2. #include <iostream>
  3.  
  4. int main()
  5. {
  6. std::locale::global(std::locale("German"));
  7. std::locale loc;
  8. std::cout << loc.name() << std::endl;
  9. }

静态函数 global() 接受一个类型为 std::locale 的对象作为其唯一的参数。 此类的另一个版本的构造函数接受类型为 const char* 的字符串,可以为一个特别的文化创建区域设置对象。 然而,除了 C 区域设置相应地命名为 "C" 之外,其他区域设置的名字并没有标准化,所以这依赖于接受区域设置名字的 C++ 标准库。 在使用 Visual Studio 2008 的情况下,语言字符串文档 指出, 可以使用语言字符串 "German" 选择定义为德国文化。

执行程序,会输出 German_Germany.1252 。 指定语言字符串为 "German" 等于选择了德国文化作为主要语言和子语言,这里选择了字符映射 1252。

如果想指定与德国文化不同的子语言设置,例如瑞士语,需要使用不同的语言字符串。

  1. #include <locale>
  2. #include <iostream>
  3.  
  4. int main()
  5. {
  6. std::locale::global(std::locale("German_Switzerland"));
  7. std::locale loc;
  8. std::cout << loc.name() << std::endl;
  9. }

现在程序会输出 German_Switzerland.1252

在初步理解了区域设置以及如何更改全局设置后, 下面的例子说明了区域设置如何影响字符串操作。

  1. #include <locale>
  2. #include <iostream>
  3. #include <cstring>
  4.  
  5. int main()
  6. {
  7. std::cout << std::strcoll("ä", "z") << std::endl;
  8. std::locale::global(std::locale("German"));
  9. std::cout << std::strcoll("ä", "z") << std::endl;
  10. }

本例使用了定义在文件 cstring 中的函数 std::strcoll() ,这个函数用于按照字典顺序比较第一个字符串是否小于第二个。 换言之,它会判断这两个字符串中哪一个在字典中靠前。

执行程序,得到结果为 1-1 。 虽然函数的参数是一样的, 却得到了不同的结果。 原因很简单,在第一次调用函数 std::strcoll() 时,使用了全局 C 区域设置; 而在第二次调用时,全局区域设置更改为德国文化。 从输出中可以看出,在这两种区域设置中,字符 'ä' 和 'z' 的次序是不同的。

很多 C 函数以及 C++ 流都与区域设置有关。 尽管类 std::string 中的函数是与区域设置独立工作的, 但是以下各节中提到的函数并不是这样。 所以,在本章中还会多次提到区域设置的相关内容。