How to convert std::string to lower case?
我想将
有没有一种方法可以100%的时间运作?
改编自不那么常见问题:
1 2 3 4 5 6 7 | #include #include <cctype> #include <string> std::string data ="Abc"; std::transform(data.begin(), data.end(), data.begin(), [](unsigned char c){ return std::tolower(c); }); |
如果不迭代每个角色,你真的不会离开。否则无法知道字符是小写还是大写。
如果你真的讨厌
1 2 3 4 5 6 7 | char asciitolower(char in) { if (in <= 'Z' && in >= 'A') return in - ('Z' - 'z'); return in; } std::transform(data.begin(), data.end(), data.begin(), asciitolower); |
请注意,
Boost为此提供了一个字符串算法:
1 2 3 4 | #include <boost/algorithm/string.hpp> std::string str ="HELLO, WORLD!"; boost::algorithm::to_lower(str); // modifies str |
或者,对于非就地:
1 2 3 4 | #include <boost/algorithm/string.hpp> const std::string str ="HELLO, WORLD!"; const std::string lower_str = boost::algorithm::to_lower_copy(str); |
TL;博士
使用ICU库。
首先,您必须回答一个问题:
如果您使用UTF-8(8位编码中唯一合理的选择)并将
只要你尝试像
然后有一点是标准库取决于运行软件的机器上支持的语言环境......如果不是,你会怎么做?
所以你真正想要的是一个能够正确处理所有这些的字符串类,而这不是任何
(C ++ 11注意:
虽然Boost看起来不错,但API智能,Boost.Locale基本上是ICU的包装器。如果使用ICU支持编译Boost ...如果不是,则Boost.Locale仅限于为标准库编译的语言环境支持。
并且相信我,让Boost与ICU一起编译可能是一个真正的痛苦。 (Windows没有预编译的二进制文件,因此您必须将它们与您的应用程序一起提供,这会打开一整套新的蠕虫......)
所以我个人建议直接从马口获得完整的Unicode支持并直接使用ICU库:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <unicode/unistr.h> #include <unicode/ustream.h> #include <unicode/locid.h> #include <iostream> int main() { char const * someString ="Eidenges\xe4\xdf"; icu::UnicodeString someUString( someString,"ISO-8859-1" ); // Setting the locale explicitly here for completeness. // Usually you would use the user-specified system locale. std::cout << someUString.toLower("de_DE" ) <<" "; std::cout << someUString.toUpper("de_DE" ) <<" "; return 0; } |
编译(在此示例中使用G ++):
1 | g++ -Wall example.cpp -licuuc -licuio |
这给出了:
1 2 | eidenges?? EIDENGES?SS |
[1] 2017年,德国正字法委员会裁定"?" U + 1E9E LATIN CAPITAL LETTER SHARP S可以正式使用,作为传统"SS"转换旁边的选项,以避免歧义,例如:在护照中(名称大写)。我美丽的例子,由委员会决定过时了......
如果字符串包含ASCII范围之外的UTF-8字符,则boost :: algorithm :: to_lower将不会转换这些字符。当涉及UTF-8时,最好使用boost :: locale :: to_lower。请参阅http://www.boost.org/doc/libs/1_51_0/libs/locale/doc/html/conversions.html
使用基于范围的C ++ 11循环,一个更简单的代码是:
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include <iostream> // std::cout #include <string> // std::string #include <locale> // std::locale, std::tolower int main () { std::locale loc; std::string str="Test String. "; for(auto elem : str) std::cout << std::tolower(elem,loc); } |
这是Stefan Mai的回复的后续行动:如果您想将转换结果放在另一个字符串中,则需要在调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #include <string> #include #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; } |
另一种使用基于范围的循环与参考变量的方法
1 2 3 4 5 6 7 | string test ="Hello World"; for(auto& c : test) { c = tolower(c); } cout<<test<<endl; |
据我所知,Boost库的性能非常糟糕。我已经测试了他们的unordered_map到STL,平均慢了3倍(最好的情况2,最差的是10次)。此算法看起来也太低了。
差异是如此之大,以至于我确信无论你需要做什么来增加
我已经在Amazon EC2上完成了这些测试,因此在测试过程中性能会有所不同,但您仍然可以理解。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ./test Elapsed time: 12365milliseconds Elapsed time: 1640milliseconds ./test Elapsed time: 26978milliseconds Elapsed time: 1646milliseconds ./test Elapsed time: 6957milliseconds Elapsed time: 1634milliseconds ./test Elapsed time: 23177milliseconds Elapsed time: 2421milliseconds ./test Elapsed time: 17342milliseconds Elapsed time: 14132milliseconds ./test Elapsed time: 7355milliseconds Elapsed time: 1645milliseconds |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ./test Elapsed time: 3769milliseconds Elapsed time: 565milliseconds ./test Elapsed time: 3815milliseconds Elapsed time: 565milliseconds ./test Elapsed time: 3643milliseconds Elapsed time: 566milliseconds ./test Elapsed time: 22018milliseconds Elapsed time: 566milliseconds ./test Elapsed time: 3845milliseconds Elapsed time: 569milliseconds |
资源:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | string str; bench.start(); for(long long i=0;i<1000000;i++) { str="DSFZKMdskfdsjfsdfJDASFNSDJFXCKVdnjsafnjsdfjdnjasnJDNASFDJDSFSDNJjdsanjfsdnfjJNFSDJFSD"; boost::algorithm::to_lower(str); } bench.end(); bench.start(); for(long long i=0;i<1000000;i++) { str="DSFZKMdskfdsjfsdfJDASFNSDJFXCKVdnjsafnjsdfjdnjasnJDNASFDJDSFSDNJjdsanjfsdnfjJNFSDJFSD"; for(unsigned short loop=0;loop < str.size();loop++) { str[loop]=tolower(str[loop]); } } bench.end(); |
我想我应该在专用机器上进行测试但是我将使用这个EC2所以我真的不需要在我的机器上测试它。
来自标准C ++ Localization库的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include <locale> #include <iostream> int main () { std::locale::global(std::locale("en_US.utf8")); std::wcout.imbue(std::locale()); std::wcout <<"In US English UTF-8 locale: "; auto& f = std::use_facet<std::ctype<wchar_t>>(std::locale()); std::wstring str = L"HELLo, wORLD!"; std::wcout <<"Lowercase form of the string '" << str <<"' is"; f.tolower(&str[0], &str[0] + str.size()); std::wcout <<"'" << str <<"' "; } |
在不打扰std命名空间的情况下将字符串转换为loweercase的最简单方法如下
1:带/不带空格的字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include #include <iostream> #include <string> using namespace std; int main(){ string str; getline(cin,str); //------------function to convert string into lowercase--------------- transform(str.begin(), str.end(), str.begin(), ::tolower); //-------------------------------------------------------------------- cout<<str; return 0; } |
2:没有空格的字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include #include <iostream> #include <string> using namespace std; int main(){ string str; cin>>str; //------------function to convert string into lowercase--------------- transform(str.begin(), str.end(), str.begin(), ::tolower); //-------------------------------------------------------------------- cout<<str; return 0; } |
有一种方法可以将大写字母转换为低级而不进行测试,而且非常简单。 isupper()函数/宏使用clocale.h应该处理与你的位置有关的问题,但如果没有,你可以随时调整UtoL []到你心脏的内容。
鉴于C的字符实际上只是8位整数(暂时忽略了宽字符集),你可以创建一个256字节的数组,其中包含一组替代字符,并且在转换函数中使用字符串中的字符作为下标。转换数组。
而不是1对1映射,为大写数组成员提供小写字符的BYTE int值。你可能会发现islower()和isupper()在这里很有用。
代码看起来像这样......
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #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; } |
同时,此方法允许您重新映射您希望更改的任何其他字符。
当在现代处理器上运行时,这种方法具有一个巨大的优势,不需要进行分支预测,因为如果测试包括分支则不存在。这为其他循环保存了CPU的分支预测逻辑,并且倾向于防止流水线停顿。
这里的一些人可能认为这种方法与用于将EBCDIC转换为ASCII的方法相同。
Boost的另一种选择是POCO(pocoproject.org)。
POCO提供两种变体:
"就地"版本的名称中始终包含"InPlace"。
两个版本如下所示:
1 2 3 4 5 6 7 8 9 10 | #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); |
如果你想要一些简单的东西,这是一个宏技术:
1 2 3 | #define STRTOLOWER(x) std::transform (x.begin(), x.end(), x.begin(), ::tolower) #define STRTOUPPER(x) std::transform (x.begin(), x.end(), x.begin(), ::toupper) #define STRTOUCFIRST(x) std::transform (x.begin(), x.begin()+1, x.begin(), ::toupper); std::transform (x.begin()+1, x.end(), x.begin()+1,::tolower) |
但请注意,@ AndreasSpindler对此答案的评论仍然是一个重要的考虑因素,但是,如果您正在处理的不仅仅是ASCII字符。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // tolower example (C++) #include <iostream> // std::cout #include <string> // std::string #include <locale> // std::locale, std::tolower int main () { std::locale loc; std::string str="Test String. "; for (std::string::size_type i=0; i<str.length(); ++i) std::cout << std::tolower(str[i],loc); return 0; } |
有关更多信息,请访问:http://www.cplusplus.com/reference/locale/tolower/
Is there an alternative which works 100% of the time?
没有
在选择小写方法之前,您需要先问几个问题。
一旦你有了这些问题的答案,你就可以开始寻找适合你需求的解决方案了。没有一种适合所有人适合所有人的尺寸!
由于没有一个答案提到了即将推出的Ranges库,它在C ++ 20之后的标准库中可用,并且目前在GitHub上单独提供为
要就地修改字符串:
1 | str |= action::transform([](unsigned char c){ return std::tolower(c); }); |
要生成新字符串:
1 2 | auto new_string = original_string | view::transform([](unsigned char c){ return std::tolower(c); }); |
(不要忘记
注意:使用
Like all other functions from
, the behavior of std::tolower is undefined if the argument's value is neither representable asunsigned char nor equal toEOF . To use these functions safely with plainchar s (orsigned char s), the argument should first be converted tounsigned char :
1
2
3
4 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 orsigned char . Instead, convert the value tounsigned char first:
1
2
3
4
5
6
7
8
9 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;
}
我自己的模板函数,执行大小写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #include <string> #include // // Lowercases string // template <typename T> std::basic_string< T > lowercase(const std::basic_string< T >& s) { std::basic_string< T > s2 = s; std::transform(s2.begin(), s2.end(), s2.begin(), tolower); return std::move(s2); } // // Uppercases string // template <typename T> std::basic_string< T > uppercase(const std::basic_string< T >& s) { std::basic_string< T > s2 = s; std::transform(s2.begin(), s2.end(), s2.begin(), toupper); return std::move(s2); } |
代码片段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include<bits/stdc++.h> using namespace std; int main () { ios::sync_with_stdio(false); string str="String Convert "; for(int i=0; i<str.size(); i++) { str[i] = tolower(str[i]); } cout<<str<<endl; return 0; } |
使用fplus :: to_lower_case()。
(fplus:https://github.com/Dobiasd/FunctionalPlus。
在http://www.editgym.com/fplus-api-search/中搜索"to_lower_case"
1 | fplus::to_lower_case(std::string("ABC")) == std::string("abc"); |
复制,因为不允许改善答案。谢谢你
1 2 3 4 5 | string test ="Hello World"; for(auto& c : test) { c = tolower(c); } |
说明:
这里自动说明符用于自动类型推导。因此,类型从变量初始值设定项中扣除。
在这种情况下,范围是字符串
字符串
C ++没有为字符串实现tolower或toupper方法,但它可用于char。可以轻松读取字符串的每个字符串,将其转换为必需的大小写并将其放回字符串中。
不使用任何第三方库的示例代码:
1 2 3 4 5 6 7 8 9 10 | #include<iostream> int main(){ std::string str = std::string("How IS The Josh"); for(char &ch : str){ ch = std::tolower(ch); } std::cout<<str<<std::endl; return 0; } |
对于字符串的基于字符的操作:对于字符串中的每个字符
在Microsoft平台上,您可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | // 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 ", string ); printf("Lower: %s ", copy1 ); printf("Upper: %s ", copy2 ); free( copy1 ); free( copy2 ); } |
这可能是另一个将大写转换为小写的简单版本,反之亦然。我使用VS2017社区版来编译这个源代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #include <iostream> #include <string> using namespace std; int main() { std::string _input ="lowercasetouppercase"; #if 0 // My idea is to use the ascii value to convert char upperA = 'A'; char lowerA = 'a'; cout << (int)upperA << endl; // ASCII value of 'A' -> 65 cout << (int)lowerA << endl; // ASCII value of 'a' -> 97 // 97-65 = 32; // Difference of ASCII value of upper and lower a #endif // 0 cout <<"Input String =" << _input.c_str() << endl; for (int i = 0; i < _input.length(); ++i) { _input[i] -= 32; // To convert lower to upper #if 0 _input[i] += 32; // To convert upper to lower #endif // 0 } cout <<"Output String =" << _input.c_str() << endl; return 0; } |
注意:如果有特殊字符,则需要使用条件检查进行处理。
我试过std :: transform,我得到的是令人讨厌的stl criptic编译错误,只有200年前的德鲁伊才能理解(不能转换为flibidi flabidi flu)
这工作正常,可以很容易地调整
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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; } |
1 2 3 4 5 6 7 | //You can really just write one on the fly whenever you need one. #include <string> void _lower_case(std::string& s){ for(unsigned short l = s.size();l;s[--l]|=(1<<5)); } //Here is an example. //http://ideone.com/mw2eDK |