我想转换一个std::字符串小写。我知道tolower()函数。然而,在过去,我有这个函数的问题,它几乎不是理想的无论如何使用std::string将需要迭代每个字符。
有没有一种替代方案能100%有效?
我想转换一个std::字符串小写。我知道tolower()函数。然而,在过去,我有这个函数的问题,它几乎不是理想的无论如何使用std::string将需要迭代每个字符。
有没有一种替代方案能100%有效?
当前回答
在微软平台上,您可以使用strlwr系列函数:http://msdn.microsoft.com/en-us/library/hkxwh33z.aspx
// crt_strlwr.c
// compile with: /W3
// This program uses _strlwr and _strupr to create
// uppercase and lowercase copies of a mixed-case string.
#include <string.h>
#include <stdio.h>
int main( void )
{
char string[100] = "The String to End All Strings!";
char * copy1 = _strdup( string ); // make two copies
char * copy2 = _strdup( string );
_strlwr( copy1 ); // C4996
_strupr( copy2 ); // C4996
printf( "Mixed: %s\n", string );
printf( "Lower: %s\n", copy1 );
printf( "Upper: %s\n", copy2 );
free( copy1 );
free( copy2 );
}
其他回答
Boost的替代方案是POCO (pocoproject.org)。
POCO提供了两种变体:
第一个变体在不改变原始字符串的情况下进行复制。 第二个变体就地更改原始字符串。 “InPlace”版本的名称中总是包含“InPlace”。
两个版本演示如下:
#include "Poco/String.h"
using namespace Poco;
std::string hello("Stack Overflow!");
// Copies "STACK OVERFLOW!" into 'newString' without altering 'hello.'
std::string newString(toUpper(hello));
// Changes newString in-place to read "stack overflow!"
toLowerInPlace(newString);
有一种方法可以在不进行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时使用的方法相同。
由于没有一个答案提到即将到来的Ranges库,它从c++ 20开始就在标准库中可用,目前在GitHub上单独可用为range-v3,我想添加一种使用它执行转换的方法。
就地修改字符串:
str |= action::transform([](unsigned char c){ return std::tolower(c); });
生成一个新的字符串:
auto new_string = original_string
| view::transform([](unsigned char c){ return std::tolower(c); });
(不要忘记#include <cctype>和所需的Ranges头。)
注意:使用unsigned char作为lambda的参数是受cppreference的启发,它声明:
Like all other functions from <cctype>, the behavior of std::tolower is undefined if the argument's value is neither representable as unsigned char nor equal to EOF. To use these functions safely with plain chars (or signed chars), the argument should first be converted to unsigned char: char my_tolower(char ch) { return static_cast<char>(std::tolower(static_cast<unsigned char>(ch))); } Similarly, they should not be directly used with standard algorithms when the iterator's value type is char or signed char. Instead, convert the value to unsigned char first: std::string str_tolower(std::string s) { std::transform(s.begin(), s.end(), s.begin(), // static_cast<int(*)(int)>(std::tolower) // wrong // [](int c){ return std::tolower(c); } // wrong // [](char c){ return std::tolower(c); } // wrong [](unsigned char c){ return std::tolower(c); } // correct ); return s; }
使用fplus库中的fplus::to_lower_case()。
在fplus API搜索中搜索到_lower_case
例子:
fplus::to_lower_case(std::string("ABC")) == std::string("abc");
有没有一种替代方案能100%有效?
No
在选择小写的方法之前,你需要问自己几个问题。
字符串是如何编码的?纯ASCII吗?utf - 8 ?某种形式的扩展ASCII遗留编码? 你说小写是什么意思?大小写映射规则因语言而异!你想要一些本地化到用户语言环境的东西吗?您希望软件在运行的所有系统上都表现一致吗?你只是想要小写ASCII字符并传递其他所有东西吗? 有哪些库可用?
一旦你有了这些问题的答案,你就可以开始寻找适合你需要的解决方案了。没有一种方法能在任何地方适用于所有人!