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

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


当前回答

使用c++ 11中基于范围的for循环,代码会更简单:

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

其他回答

有一种方法可以在不进行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;
}

std::ctype::tolower()从标准c++本地化库将正确地为您做这件事。下面是一个例子,从下面的参考页面提取

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

改编自《不常见问题》:

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

如果不遍历每个字符,你真的无法逃脱。否则就无法知道字符是小写还是大写。

如果你真的讨厌ower(),这里有一个专门的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);

请注意,tolower()只能执行单个字节的字符替换,这不适用于许多脚本,特别是在使用UTF-8这样的多字节编码时。

这可能是另一个简单的版本,将大写字母转换为小写字母,反之亦然。我使用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;
}

注意:如果有特殊字符,则需要使用条件检查来处理。