我想转换一个std::字符串小写。我知道tolower()函数。然而,在过去,我有这个函数的问题,它几乎不是理想的无论如何使用std::string将需要迭代每个字符。

有没有一种替代方案能100%有效?


当前回答

试试这个函数吧。

string toLowerCase(string str) {

    int str_len = str.length();

    string final_str = "";

    for(int i=0; i<str_len; i++) {

        char character = str[i];

        if(character>=65 && character<=92) {

            final_str += (character+32);

        } else {

            final_str += character;

        }

    }

    return final_str;

}

其他回答

我写了一个模板版本,适用于任何字符串:

#include <type_traits> // std::decay
#include <ctype.h>    // std::toupper & std::tolower


template <class T = void> struct farg_t { using type = T; };
template <template<typename ...> class T1, 
class T2> struct farg_t <T1<T2>> { using type = T2*; };
//---------------

template<class T, class T2 = 
typename std::decay< typename farg_t<T>::type >::type>
void ToUpper(T& str) { T2 t = &str[0]; 
for (; *t; ++t) *t = std::toupper(*t); }


template<class T, class T2 = typename std::decay< typename 
farg_t<T>::type >::type>
void Tolower(T& str) { T2 t = &str[0]; 
for (; *t; ++t) *t = std::tolower(*t); }

用gcc编译器测试:

#include <iostream>
#include "upove_code.h"

int main()
{

    std::string str1 = "hEllo ";
    char str2 [] = "wOrld";

    ToUpper(str1);
    ToUpper(str2);
    std::cout << str1 << str2 << '\n'; 
    Tolower(str1);
    Tolower(str2);
    std::cout << str1 << str2 << '\n'; 
    return 0;
}

输出:

>HELLO WORLD
>
>hello world

如果字符串包含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

有一种方法可以在不进行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时使用的方法相同。

使用此代码在c++中更改字符串的大小写。

#include<bits/stdc++.h>

using namespace std;

int main(){
  string a = "sssAAAAAAaaaaDas";
  transform(a.begin(),a.end(),a.begin(),::tolower);
  cout<<a;
}

我自己的模板函数,执行大写/小写。

#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 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 s2;
}