我想转换一个std::字符串小写。我知道tolower()函数。然而,在过去,我有这个函数的问题,它几乎不是理想的无论如何使用std::string将需要迭代每个字符。
有没有一种替代方案能100%有效?
我想转换一个std::字符串小写。我知道tolower()函数。然而,在过去,我有这个函数的问题,它几乎不是理想的无论如何使用std::string将需要迭代每个字符。
有没有一种替代方案能100%有效?
当前回答
有没有一种替代方案能100%有效?
No
在选择小写的方法之前,你需要问自己几个问题。
字符串是如何编码的?纯ASCII吗?utf - 8 ?某种形式的扩展ASCII遗留编码? 你说小写是什么意思?大小写映射规则因语言而异!你想要一些本地化到用户语言环境的东西吗?您希望软件在运行的所有系统上都表现一致吗?你只是想要小写ASCII字符并传递其他所有东西吗? 有哪些库可用?
一旦你有了这些问题的答案,你就可以开始寻找适合你需要的解决方案了。没有一种方法能在任何地方适用于所有人!
其他回答
另一种方法是使用带参考变量的基于范围的for循环
string test = "Hello World";
for(auto& c : test)
{
c = tolower(c);
}
cout<<test<<endl;
使用fplus库中的fplus::to_lower_case()。
在fplus API搜索中搜索到_lower_case
例子:
fplus::to_lower_case(std::string("ABC")) == std::string("abc");
我写了这个简单的helper函数:
#include <locale> // tolower
string to_lower(string s) {
for(char &c : s)
c = tolower(c);
return s;
}
用法:
string s = "TEST";
cout << to_lower("HELLO WORLD"); // output: "hello word"
cout << to_lower(s); // won't change the original variable.
复制是因为不允许改进答案。谢谢所以
string test = "Hello World";
for(auto& c : test)
{
c = tolower(c);
}
解释:
For (auto& c: test)是一个基于范围的For循环,类似于For (range_declaration:range_expression)loop_statement:
Range_declaration: auto& c 这里auto说明符用于自动类型推断。类型从变量初始化式中扣除。 range_expression:测试 本例中的范围是字符串test的字符。
字符串test的字符可以在for循环中通过标识符c作为引用。
博士tl;
使用ICU图书馆。如果您不这样做,您的转换例程将在您可能甚至没有意识到存在的情况下无声地中断。
首先你必须回答一个问题:std::string的编码是什么?是ISO-8859-1吗?或者ISO-8859-8?或者Windows Codepage 1252?不管你用什么来转换大写字母还是小写字母,你知道吗?(或者对于0x7f以上的字符会失败吗?)
如果您使用UTF-8(8位编码中唯一明智的选择)和std::string作为容器,如果您认为您仍然在控制事情,那么您已经欺骗了自己。您正在将一个多字节字符序列存储在一个不知道多字节概念的容器中,您可以对其执行的大多数操作也不知道多字节的概念!即使是像.substr()这样简单的东西也可能导致无效的(子)字符串,因为您在多字节序列中间进行了分割。
As soon as you try something like std::toupper( 'ß' ), or std::tolower( 'Σ' ) in any encoding, you are in trouble. Because 1), the standard only ever operates on one character at a time, so it simply cannot turn ß into SS as would be correct. And 2), the standard only ever operates on one character at a time, so it cannot decide whether Σ is in the middle of a word (where σ would be correct), or at the end (ς). Another example would be std::tolower( 'I' ), which should yield different results depending on the locale -- virtually everywhere you would expect i, but in Turkey ı (LATIN SMALL LETTER DOTLESS I) is the correct answer (which, again, is more than one byte in UTF-8 encoding).
因此,任何一次处理一个字符的大小写转换,或者更糟,一次处理一个字节的大小写转换,都在设计上被破坏了。这包括目前存在的所有std::变体。
还有一点,标准库能够做什么,取决于运行软件的机器支持哪些地区…如果您的目标区域位于客户机上不支持的区域之一,该怎么办?
因此,您真正要寻找的是一个能够正确处理所有这些问题的字符串类,而不是std::basic_string<>变量。
(c++ 11注:std::u16string和std::u32string较好,但仍不完美。c++ 20带来了std::u8string,但所有这些都是指定编码。在许多其他方面,他们仍然对Unicode机制一无所知,比如标准化、排序……)
虽然Boost看起来不错,API方面,Boost。Locale基本上是ICU的包装器。如果Boost是使用ICU支持编译的……如果不是,Boost。区域设置仅限于为标准库编译的区域设置支持。
相信我,让Boost与ICU一起编译有时真的很痛苦。(Windows中没有包含ICU的预编译二进制文件,所以你必须在应用程序中提供它们,这就打开了一个全新的蠕虫…)
所以我个人建议直接从马的嘴里获得完整的Unicode支持,并直接使用ICU库:
#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <unicode/locid.h>
#include <iostream>
int main()
{
/* "Odysseus" */
char const * someString = u8"ΟΔΥΣΣΕΥΣ";
icu::UnicodeString someUString( someString, "UTF-8" );
// Setting the locale explicitly here for completeness.
// Usually you would use the user-specified system locale,
// which *does* make a difference (see ı vs. i above).
std::cout << someUString.toLower( "el_GR" ) << "\n";
std::cout << someUString.toUpper( "el_GR" ) << "\n";
return 0;
}
编译(本例中使用g++):
g++ -Wall example.cpp -licuuc -licuio
这给:
ὀδυσσεύς
注意,单词中间的Σ<-> Σ转换,单词末尾的Σ<->ς转换。没有<算法>的解决方案可以给你。