我想转换一个 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

或者,对于非IN-位置

#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提供了两种变体:

  1. 第一个变种的副本,而不改变原来的字符串。
  2. 第二种改变原来的字符串中的地方。
    "就地"的版本,一直有"就地"的名称。

这两个版本都有说明如下:

#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%的时间?

没有

有几个问题你需要问问自己之前选择一个小写转换的方法。

  1. 怎么是串编码的?纯ASCII?UTF-8?某些形式的扩展ASCII旧编码?
  2. 你是什么意思由的情况下?情况映的规则之间有所不同的语言!你想要的东西,是本地化的用户区域设置?你想要的东西,其行为一贯在所有的系统软件运行?你只是想要小写ASCII字符和通过其他一切?
  3. 什么图书馆?

一旦你已经回答这些问题,你可以开始寻找一个解适合你的需要。没有一种尺寸适合所有适用于每一个人无处不在!

由于没有任何答复中提到的即将到来的范围,图书馆,这是在图书馆标准由于用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.使用这些功能安全地与普通的 chars(或 signed chars),论点应该首先被转换成 unsigned char:

char my_tolower(char ch)
{
    return static_cast<char>(std::tolower(static_cast<unsigned char>(ch)));
}

同样,他们不应该直接使用的标准算法时的迭代的价值类型 charsigned 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:

  1. range_declaration: auto& c
    这里的 自动说明 用于自动类型扣除。此类被扣除的变量的初始化程序。

  2. 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
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top