我想转换一个std::字符串小写。我知道tolower()函数。然而,在过去,我有这个函数的问题,它几乎不是理想的无论如何使用std::string将需要迭代每个字符。
有没有一种替代方案能100%有效?
我想转换一个std::字符串小写。我知道tolower()函数。然而,在过去,我有这个函数的问题,它几乎不是理想的无论如何使用std::string将需要迭代每个字符。
有没有一种替代方案能100%有效?
当前回答
这是Stefan Mai的回应的后续:如果你想把转换的结果放在另一个字符串中,你需要在调用std::transform之前预先分配它的存储空间。由于STL将转换后的字符存储在目标迭代器中(在每次循环迭代时递增),因此目标字符串不会自动调整大小,并且可能会占用内存。
#include <string>
#include <algorithm>
#include <iostream>
int main (int argc, char* argv[])
{
std::string sourceString = "Abc";
std::string destinationString;
// Allocate the destination space
destinationString.resize(sourceString.size());
// Convert the source string to lower case
// storing the result in destination string
std::transform(sourceString.begin(),
sourceString.end(),
destinationString.begin(),
::tolower);
// Output the result of the conversion
std::cout << sourceString
<< " -> "
<< destinationString
<< std::endl;
}
其他回答
因为你正在使用std::string,你正在使用c++。如果使用c++11或更高版本,则不需要任何花哨的东西。如果words是vector<string>,那么:
for (auto & str : words) {
for(auto & ch : str)
ch = tolower(ch);
}
没有奇怪的异常。可能想要使用w_char's,但除此之外,这应该全部到位。
我尝试了std::transform,我得到的是可恶的stl criptic编译错误,只有200年前的德鲁伊才能理解(不能从flibidi flabidi流感转换)
这工作得很好,可以很容易地调整
string LowerCase(string s)
{
int dif='a'-'A';
for(int i=0;i<s.length();i++)
{
if((s[i]>='A')&&(s[i]<='Z'))
s[i]+=dif;
}
return s;
}
string UpperCase(string s)
{
int dif='a'-'A';
for(int i=0;i<s.length();i++)
{
if((s[i]>='a')&&(s[i]<='z'))
s[i]-=dif;
}
return s;
}
有一种方法可以在不进行if测试的情况下将大写字母转换为小写字母,而且非常简单。isupper()函数/宏对clocale.h的使用应该可以解决与您的位置相关的问题,但如果没有,您可以随时根据自己的需要调整UtoL[]。
假设C语言的字符实际上只是8位整型(暂时忽略宽字符集),您可以创建一个256字节的数组,保存另一组字符,并在转换函数中使用字符串中的字符作为转换数组的下标。
但是,不是1对1的映射,而是为小写字符赋予大写数组成员BYTE int值。你可能会发现islower()和isupper()在这里很有用。
代码看起来是这样的……
#include <clocale>
static char UtoL[256];
// ----------------------------------------------------------------------------
void InitUtoLMap() {
for (int i = 0; i < sizeof(UtoL); i++) {
if (isupper(i)) {
UtoL[i] = (char)(i + 32);
} else {
UtoL[i] = i;
}
}
}
// ----------------------------------------------------------------------------
char *LowerStr(char *szMyStr) {
char *p = szMyStr;
// do conversion in-place so as not to require a destination buffer
while (*p) { // szMyStr must be null-terminated
*p = UtoL[*p];
p++;
}
return szMyStr;
}
// ----------------------------------------------------------------------------
int main() {
time_t start;
char *Lowered, Upper[128];
InitUtoLMap();
strcpy(Upper, "Every GOOD boy does FINE!");
Lowered = LowerStr(Upper);
return 0;
}
与此同时,这种方法允许您重新映射希望更改的任何其他字符。
当在现代处理器上运行时,这种方法有一个巨大的优势,不需要做分支预测,因为没有包含分支的if测试。这为其他循环节省了CPU的分支预测逻辑,并倾向于防止管道停顿。
这里的一些人可能认识到这种方法与将EBCDIC转换为ASCII时使用的方法相同。
有没有一种替代方案能100%有效?
No
在选择小写的方法之前,你需要问自己几个问题。
字符串是如何编码的?纯ASCII吗?utf - 8 ?某种形式的扩展ASCII遗留编码? 你说小写是什么意思?大小写映射规则因语言而异!你想要一些本地化到用户语言环境的东西吗?您希望软件在运行的所有系统上都表现一致吗?你只是想要小写ASCII字符并传递其他所有东西吗? 有哪些库可用?
一旦你有了这些问题的答案,你就可以开始寻找适合你需要的解决方案了。没有一种方法能在任何地方适用于所有人!
使用c++ 11中基于范围的for循环,代码会更简单:
#include <iostream> // std::cout
#include <string> // std::string
#include <locale> // std::locale, std::tolower
int main ()
{
std::locale loc;
std::string str="Test String.\n";
for(auto elem : str)
std::cout << std::tolower(elem,loc);
}