21

鉴于string foo,我已经写了关于如何使用's将字符转换为小写的答案cctypetolower

transform(cbegin(foo), cend(foo), begin(foo), static_cast<int (*)(int)>(tolower))

但我已经开始考虑 locale's tolower,可以这样使用:

use_facet<ctype<char>>(cout.getloc()).tolower(data(foo), next(data(foo), foo.size()));
  • 是否有理由更喜欢其中一个而不是另一个?
  • 它们的功能有什么不同吗?
  • 我的意思是除了tolower接受并返回int我认为只是一些过时的 C 东西的事实吗?
4

3 回答 3

6

不幸的是,两者都同样糟糕。虽然std::string 假装是 utf-8 编码的字符串,但没有方法/函数(包括 tolower)真的是 utf-8 感知的。因此,tolower/ tolower+ 语言环境可能适用于单字节(= ASCII)的字符,它们对于其他所有语言集都将失败。

在 Linux 上,我会使用 ICU 库。在 Windows 上,我会使用CharUpper函数。

于 2016-05-27T12:47:42.440 回答
4

在第一种情况下(cctype),语言环境是隐式设置的:

根据当前安装的 C 语言环境定义的字符转换规则将给定字符转换为小写。

http://en.cppreference.com/w/cpp/string/byte/tolower

在第二种(语言环境)的情况下,您必须明确设置语言环境:

如果 c 是大写字母并且具有等效的小写字母,则将参数 c 转换为其等效的小写字母,由 locale loc 的 ctype facet 确定。如果不可能进行这样的转换,则返回的值是 c 不变。

http://www.cplusplus.com/reference/locale/tolower/

于 2016-05-27T11:48:32.920 回答
1

应该注意的是,语言设计者知道' cctypes是tolower什么时候创建的。它在两个主要方面有所改进:localetolower

  1. 正如progressive_overload的回答中提到的那样,该locale版本允许使用facet ctype,即使用户修改了一个,也不需要改组新LC_CTYPE的通孔setlocale并恢复以前的通孔LC_CTYPE
  2. 从第 7.1.6.2[dcl.type.simple]3 节开始:

char类型的对象是表示为有符号量还是无符号量是实现定义的。说明signed符强制char对对象进行签名

如果是参数,这会使用 's的cctype版本创建未定义行为的可能性:tolower

不可表示为unsigned char且不等于EOF

所以yielding的版本static_cast需要额外的输入输出:cctypetolower

transform(cbegin(foo), cend(foo), begin(foo), [](const unsigned char i){ return tolower(i); });

由于locale版本直接在chars 上运行,因此不需要进行类型转换。

因此,如果您不需要以不同的方式执行转换,那么facet ctype它只是一个样式问题,即您是否更喜欢版本transform所需的 lambda cctype,或者您是否更喜欢locale版本:

use_facet<ctype<char>>(cout.getloc()).tolower(data(foo), next(data(foo), size(foo)));
于 2016-06-02T13:25:11.337 回答