如何将性病::string以下情况?
-
10-07-2019 - |
题
我想转换一个 std::string
小写。我知道的功能 tolower()
, 然而在过去,我曾问题,这个功能和它几乎是不理想无论如何作用 std::string
将需要循环的每个字符。
是否有替代其工程的100%的时间?
解决方案
#include <algorithm>
#include <cctype>
#include <string>
std::string data = "Abc";
std::transform(data.begin(), data.end(), data.begin(),
[](unsigned char c){ return std::tolower(c); });
你真的不打算脱身,而无需通过每个字符迭代。有没有办法知道的字符是否是小写或以其他方式大写。
如果你真的很讨厌 tolower()
,这里有一个专门的ASCII唯一的替代方案,我不建议你使用:
char asciitolower(char in) {
if (in <= 'Z' && in >= 'A')
return in - ('Z' - 'z');
return in;
}
std::transform(data.begin(), data.end(), data.begin(), asciitolower);
注意,<=>只能做每单字节字符替换,这是不合适的许多脚本,特别是如果使用多字节编码状UTF-8。
其他提示
#include <boost/algorithm/string.hpp>
std::string str = "HELLO, WORLD!";
boost::algorithm::to_lower(str); // modifies str
#include <boost/algorithm/string.hpp>
const std::string str = "HELLO, WORLD!";
const std::string lower_str = boost::algorithm::to_lower_copy(str);
<强> TL;博士强>
使用的 ICU库。强>
首先,你必须回答一个问题:什么是的编码的你std::string
的?它是ISO-8859-1?或许ISO-8859-8?或Windows代码页1252?的无论是否你使用的转换上到小写知道?的(或者它惨遭失败的字符在0x7f
?)
如果使用的是UTF-8(8位编码中唯一明智的选择)作为.substr()
容器,你已经欺骗自己,以为你还在控制的事情,因为你存储在一个容器,它不知道多字节概念的多字节字符序列。即使是一些为std::toupper( 'ß' )
是一个滴答作响的定时炸弹一样简单。 (由于分割的多字节序列将导致一个无效的(子)字符串)。
而一旦你尝试类似"SS"
中的任何的编码,你是大麻烦。 (因为它根本不可能做到这一点“右”与标准的库,它只能传送一个结果文字,而不是这里std::tolower( 'I' )
需要的。)[1]另一个例子是<= >,这应该产生不同的结果的取决于区域设置。在德国,'i'
是正确的;在土耳其,'ı'
(拉丁小写字母带点I)是预期的结果(这又是UTF-8编码多于一个字节)。
再有就是在其语言环境的支持的机器上的软件上运行...和你做什么,如果它不是标准库取决于点?
你是那么的真正的寻找的是一个字符串类是能够处理这一切正常,的,这是的不的std::u16string
强>
(C ++ 11注:std::u32string
和<=>是更好,但还不够完善)
虽然升压看起来好的,API明智的,Boost.Locale基本上是一个包装周围 ICU 。 如果升压是的编译的ICU与支持......如果不是,Boost.Locale仅限于编译为标准库的语言环境支持。
相信我,获得的频加速至编译ICU可以是一个真正的痛苦的时候。 (目前的Windows没有预编译的二进制文件,所以你必须与你的应用程序一起提供给他们,和的是的蠕虫病毒打开了一个全新的能...)
所以,我个人会建议从马的嘴直接获得完整的Unicode支持,并直接使用 ICU 库:
#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" ) << "\n";
std::cout << someUString.toUpper( "de_DE" ) << "\n";
return 0;
}
编译(与G ++在这个例子中):
g++ -Wall example.cpp -licuuc -licuio
这给出了:
eidengesäß
EIDENGESÄSS
[1] 2017年,在德语正写法协会裁决“ẞ” U + 1E9E LATIN CAPITAL LETTER声s可以正式使用,作为传统的“SS”转换旁一个选项,以避免歧义例如在护照(其中名称是大写)。我的美丽去到例如,由委员会决定而过时......
如果字符串包含ASCII范围之外UTF-8字符,然后升压::算法:: to_lower不会转换那些。更好地利用升压::区域:: to_lower当UTF-8参与。见 http://www.boost.org/doc/libs/1_51_0 /libs/locale/doc/html/conversions.html
使用范围为基础的的C ++ 11环更简单的代码将是:
#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);
}
这是一个后续斯特凡麦的回答是:如果你想放置在另一个字符串转换的结果,你需要它的存储空间调用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;
}
基于与参考可变环使用范围的另一种方法
string test = "Hello World";
for(auto& c : test)
{
c = tolower(c);
}
cout<<test<<endl;
据我看到Boost库是非常糟糕的表现,明智的。我已经测试其unordered_map到STL,它是平均3倍慢(最好情况2中,最严重的是10次)。同样在此算法看起来太低。
在差异如此之大,我相信任何另外,你需要做的tolower
使其等于提高“您的需求”会的办法更快的比提升。
我做这些测试在Amazon EC2,在测试过程中的表现,因此改变,但你仍然有想法。
./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
<强> -O2
制成这样的:强>
./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
来源:
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所以我并不真的需要测试它在我的机器上。
最简单的方法字符串转换成loweercase,而不会打扰约std名字空间是如下
1:串带/不带空格
#include <algorithm>
#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:字符串不带空格
#include <algorithm>
#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;
}
std::ctype::tolower()
从标准C ++本地化库将正确为你做这个。下面是从提取的示例tolower的参考页
#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:\n";
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 << "'\n";
}
一种替代的提升是POCO(pocoproject.org).
POCO提供了两种变体:
- 第一个变种的副本,而不改变原来的字符串。
- 第二种改变原来的字符串中的地方。
"就地"的版本,一直有"就地"的名称。
这两个版本都有说明如下:
#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);
有是转换大写降低办法WITHOUT如果测试做的,这是非常直接的。该isupper()函数/宏的使用clocale.h的应该照顾与你的位置问题,但如果没有,你可以随时调整的UtoL []你的心脏的内容。
由于C'S字符其实只是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;
}
这个方法将在同一时间,让你重新映射你想改变任何其他字符。
这方法对现代处理器上运行时,就没有必要做的分支预测,因为不存在如果测试包括分支一个巨大的优势。这节省了CPU的分支预测逻辑的其他循环,并有利于防止流水线暂停。
一些这里可以识别这种方法称为用于转换EBCDIC到ASCII的相同。
下面是一个宏观的技术,如果你想要的东西很简单:
#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字符。
// 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.\n";
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的/
是否有替代其工程的100%的时间?
没有
有几个问题你需要问问自己之前选择一个小写转换的方法。
- 怎么是串编码的?纯ASCII?UTF-8?某些形式的扩展ASCII旧编码?
- 你是什么意思由的情况下?情况映的规则之间有所不同的语言!你想要的东西,是本地化的用户区域设置?你想要的东西,其行为一贯在所有的系统软件运行?你只是想要小写ASCII字符和通过其他一切?
- 什么图书馆?
一旦你已经回答这些问题,你可以开始寻找一个解适合你的需要。没有一种尺寸适合所有适用于每一个人无处不在!
由于没有任何答复中提到的即将到来的范围,图书馆,这是在图书馆标准由于用C++20,目前分别适用 上。 作为 range-v3
, 我想添加一种方式来执行这一转换使用。
修改的字符串中的地位:
str |= action::transform([](unsigned char c){ return std::tolower(c); });
产生一个新的string:
auto new_string = original_string
| view::transform([](unsigned char c){ return std::tolower(c); });
(不要忘记 #include <cctype>
和所需范围的标题。)
注:使用 unsigned char
作为参数,以lambda是灵感 cppreference, ,其中规定:
像所有其他的功能
<cctype>
, 行为std::tolower
是不确定如果参数的数值是不可表示为unsigned char
也不等于EOF
.使用这些功能安全地与普通的char
s(或signed char
s),论点应该首先被转换成unsigned char
:char my_tolower(char ch) { return static_cast<char>(std::tolower(static_cast<unsigned char>(ch))); }
同样,他们不应该直接使用的标准算法时的迭代的价值类型
char
或signed char
.相反,转换的价值来unsigned char
第一: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; }
在微软平台上可以使用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 );
}
代码段
#include<bits/stdc++.h>
using namespace std;
int main ()
{
ios::sync_with_stdio(false);
string str="String Convert\n";
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 'to_lower_case' -search / )
fplus::to_lower_case(std::string("ABC")) == std::string("abc");
复制,因为它是不允许以提高答复。谢谢所以
string test = "Hello World";
for(auto& c : test)
{
c = tolower(c);
}
说明:
for(auto& c : test)
是一个 基于范围的循环 的那种
for (
range_declaration
:
range_expression
)
loop_statement
:
range_declaration
:auto& c
这里的 自动说明 用于自动类型扣除。此类被扣除的变量的初始化程序。range_expression
:test
的范围内在这种情况下都字符串test
.
字符串 test
都可以作为一个参考内为循环,通过标识符 c
.
C ++不具有tolower的或在toupper字符串实现的方法,但它是可用于炭。人们可以轻松读取字符串的字符每次,将其转换成所需的案例,并把它放回字符串。 而无需使用任何第三方库的样品代码:
#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;
}
有关的字符串字符基于操作:对于字符串中的每个字符
我自己的模板函数。
#include <string>
#include <algorithm>
//
// 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);
}
这可以是另一个简单的版本来转换大写为小写,反之亦然。我用VS2017社区版本编译此源代码。
#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 ::变换,我得到的是恶劣的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;
}
//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