【问题标题】:How to convert an instance of std::string to lower case如何将 std::string 的实例转换为小写
【发布时间】:2010-09-23 18:14:15
【问题描述】:

我想将std::string 转换为小写。我知道函数tolower()。然而,在过去我遇到过这个函数的问题,无论如何它都不是理想的,因为将它与 std::string 一起使用需要遍历每个字符。

是否有其他 100% 有效的替代方案?

【问题讨论】:

  • 在不遍历列表的情况下,您如何将任何列表中的每个元素转换为其他元素?字符串只是一个字符列表,如果你需要对每个字符应用一些函数,你将不得不遍历字符串。没办法。
  • 为什么这个问题会降低评分?我在遍历我的字符串时没有问题,但我想问除了 tolower()、toupper() 等之外是否还有其他函数。
  • 如果你有一个 C 风格的 char 数组,那么我猜你可以将 ox20202020 添加到每个 4 个字符的块中(前提是它们都已经大写),一次将 4 个字符转换为小写.
  • @Dan:如果它们可能已经是小写字母,但肯定是 A-Z 或 a-z,您可以使用 0x20 或而不是添加。几乎不值得的那些非常聪明的优化之一......
  • 我不知道为什么它会被否决......当然它的措辞有点奇怪(因为你必须以某种方式遍历每个项目),但这是一个有效的问题

标签: c++ string c++-standard-library tolower


【解决方案1】:

Boost provides a string algorithm for this:

#include <boost/algorithm/string.hpp>

std::string str = "HELLO, WORLD!";
boost::algorithm::to_lower(str); // modifies str

Or, for non-in-place:

#include <boost/algorithm/string.hpp>

const std::string str = "HELLO, WORLD!";
const std::string lower_str = boost::algorithm::to_lower_copy(str);

【讨论】:

  • 非 ASCII-7 失败。
  • 这很慢,看这个基准:godbolt.org/z/neM5jsva1
【解决方案2】:

改编自Not So Frequently Asked Questions

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

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

【讨论】:

  • (可能是旧的,所讨论的算法变化不大)@Stefan Mai:调用 STL 算法会有什么样的“大量开销”?这些函数相当精简(即简单的 for 循环)并且经常内联,因为您很少在同一个编译单元中使用相同的模板参数多次调用同一个函数。
  • 每次你假设字符是 ASCII,上帝就杀了一只小猫。 :(
  • 您的第一个示例可能具有未定义的行为(将char 传递给::tolower(int)。)您需要确保没有传递负值。
  • -1 使用::tolower 可能会崩溃,它是用于非ASCII 输入的UB。
  • 在 tolower 之前需要 :: 表示它在最外层的命名空间中。如果您在另一个命名空间中使用此代码,则可能会有不同(可能不相关)的 tolower 定义,最终会在没有 :: 的情况下被优先选择。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

    这是对 Stefan Mai 的回应:如果您想将转换结果放在另一个字符串中,您需要在调用 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;
    }
    

    【讨论】:

    • 这并没有为我将 Ä 调整为 ä
    • 这里也可以使用后插入迭代器而不是手动调整大小。
    【解决方案5】:

    Boost 的替代品是 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);
    

    【讨论】:

      【解决方案6】:

      使用 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);
      }
      

      【讨论】:

      • 但是,在法语机器上,该程序不会转换法语语言中允许的非 ASCII 字符。例如字符串'Test String123. É Ï\n' 将转换为:'test string123. É Ï\n' 尽管字符 É Ï 和它们的小写字母 'é' 和 'ï' 在法语中是允许的。该线程的其他消息似乎没有提供解决方案。
      • 我认为您需要为此设置适当的语言环境。
      • @incises,然后有人发布了关于 ICU 的答案,这当然是要走的路。比尝试理解语言环境的大多数其他解决方案更容易。
      • 我个人希望尽可能不使用外部库。
      【解决方案7】:

      有一种方法可以将大写转换为小写无需进行 if 测试,而且非常简单。 isupper() 函数/宏对 clocale.h 的使用应该可以解决与您的位置相关的问题,但如果没有,您可以随时调整 UtoL[] 以适应您的需要。

      鉴于 C 的字符实际上只是 8 位整数(暂时忽略宽字符集),您可以创建一个 256 字节数组来保存一组替代字符,并在转换函数中使用字符串中的字符作为下标到转换数组中。

      虽然不是 1 对 1 映射,而是为大写数组成员提供小写字符的 BYTE int 值。您可能会发现 islower() and 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 的方法相同。

      【讨论】:

      • “有一种方法可以在不进行 if 测试的情况下将大写转换为小写”听说过查找表吗?
      • 负字符的未定义行为。
      • 现代 CPU 的瓶颈在于内存而非 CPU。基准测试会很有趣。
      【解决方案8】:

      tl;dr

      使用ICU library如果你不这样做,你的转换例程会在你可能不知道存在的情况下静默中断。


      首先你要回答一个问题:你的std::string编码是什么?是 ISO-8859-1 吗?或者也许是 ISO-8859-8?还是 Windows 代码页 1252? 您用于将大写转换为小写的任何东西都知道吗?(或者对于超过0x7f 的字符,它是否会失败?)

      如果您使用 UTF-8 (the only sane choice among the 8-bit encodings) 和 std::string 作为容器,如果您认为您仍然可以控制事物,那么您已经在欺骗自己了。您将多字节字符序列存储在不了解多字节概念的容器中,并且您可以对其执行的大多数操作也不是!即使像.substr() 这样简单的东西也可能导致无效(子)字符串,因为您在多字节序列的中间进行拆分。

      一旦您尝试像std::toupper( 'ß' )std::tolower( 'Σ' ) 之类的any 编码,您就有麻烦了。因为 1),该标准一次只对一个字符进行操作,所以它根本无法将 ß 转换为 SS 是正确的。并且 2),该标准一次只对一个字符进行操作,因此它无法确定 Σ 是在单词的中间(σ 是正确的),还是在末尾(ς) .另一个例子是std::tolower( 'I' ),它应该会产生不同的结果取决于语言环境 - 几乎所有你会想到i,但在土耳其ı(拉丁小写字母DOTLESS I)是正确答案(同样,在 UTF-8 编码中超过一个字节)。

      因此,任何 一次对一个字符起作用的大小写转换,或者更糟糕的是,一次对一个字节 起作用的转换都被设计破坏了。 strong> 这包括目前存在的所有std:: 变体。

      还有一点是,标准库 能够做什么取决于运行软件的机器上支持 的区域设置...如果您的目标语言环境在您的客户机器上不受支持,您会怎么做?

      所以您真正要寻找的是一个能够正确处理所有这些的字符串类,不是任何@987654341 @变体

      (C++11 注意:std::u16stringstd::u32string 更好,但仍然不完美。C++20 带来了std::u8string,但所有这些都是指定 >编码。在许多其他方面,他们仍然对 Unicode 机制一无所知,例如规范化、排序规则……)

      虽然 Boost 看起来不错,但在 API 方面,Boost.Locale 基本上是 ICU 的包装器。 如果 Boost 是编译 ICU 支持...如果不是,Boost.Locale 仅限于为标准库编译的语言环境支持。

      相信我,获得 Boost 与 ICU 一起编译有时会很痛苦。 (包含 ICU 的 Windows 没有预编译的二进制文件,因此您必须将它们与您的应用程序一起提供,并且 会打开一个全新的蠕虫罐...)

      所以我个人建议直接从马口中获得完整的 Unicode 支持并直接使用 ICU 库:

      #include <unicode/unistr.h>
      #include <unicode/ustream.h>
      #include <unicode/locid.h>
      
      #include <iostream>
      
      int main()
      {
          /*                          "Odysseus" */
          char const * someString = u8"ΟΔΥΣΣΕΥΣ";
          icu::UnicodeString someUString( someString, "UTF-8" );
          // Setting the locale explicitly here for completeness.
          // Usually you would use the user-specified system locale,
          // which *does* make a difference (see ı vs. i above).
          std::cout << someUString.toLower( "el_GR" ) << "\n";
          std::cout << someUString.toUpper( "el_GR" ) << "\n";
          return 0;
      }
      

      编译(本例中使用 G++):

      g++ -Wall example.cpp -licuuc -licuio
      

      这给出了:

      ὀδυσσεύς
      

      注意单词中间的Σσ转换,单词末尾的Σς转换。没有基于&lt;algorithm&gt; 的解决方案可以为您提供。

      【讨论】:

      • 这是一般情况下的正确答案。除了谎言和欺骗之外,该标准没有提供任何处理任何东西的东西,除了“ASCII”。它让你认为你也许可以处理 UTF-16,但你不能。正如这个答案所说,如果不进行自己的 unicode 处理,就无法获得 UTF-16 字符串的正确字符长度(不是字节长度)。如果您必须处理真实文本,请使用 ICU。谢谢,@DevSolar
      • ICU 在 Ubuntu/Windows 上默认可用还是需要单独安装?另外这个答案怎么样:stackoverflow.com/a/35075839/207661
      • icu::UnicodeString::length() 从技术上讲也是在骗你(尽管频率较低),因为它报告的是 16 位代码单元的数量而不是代码点的数量。 ;-)
      • @masaers:公平地说,对于组合字符、零宽度连接符和从右到左标记之类的东西,代码点的数量毫无意义。我将删除该评论。
      • @DevSolar 同意!长度的概念在文本上是毫无意义的(我们可以在违规者列表中添加连字)。也就是说,由于人们习惯于制表符和控制字符占用一个长度单位,因此代码点将是更直观的度量。哦,谢谢你给出正确的答案,很遗憾看到它这么远:-(
      【解决方案9】:

      我尝试了 std::transform,我得到的只是可恶的 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;
      }
      

      【讨论】:

        【解决方案10】:

        在 microsoft 平台上,您可以使用 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 );
        }
        

        【讨论】:

          【解决方案11】:

          将字符串转换为小写而不用关心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;
          }
          

          【讨论】:

            【解决方案12】:

            标准 C++ 本地化库中的std::ctype::tolower() 将为您正确执行此操作。这是从tolower reference page中提取的示例

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

            【讨论】:

            • 很好,只要你能将字符转换到位。如果您的源字符串是const 怎么办?这似乎使它有点混乱(例如,看起来您不能使用 f.tolower() ),因为您需要将字符放入新字符串中。您会使用transform()std::bind1st( std::mem_fun() ) 之类的东西作为运算符吗?
            • 对于一个 const 字符串,我们可以只制作一个本地副本,然后就地转换。
            • 是的,不过,制作副本会增加更多开销。
            • 您可以将 std::transform 与不带指针的 ctype::tolower 版本一起使用。使用后插入迭代器适配器,您甚至无需担心预先调整输出字符串的大小。
            • 很好,特别是因为在 libstdc++ 的 tolowerlocale 参数中,对 use_facet 的隐式调用似乎是一个性能瓶颈。我的一位同事通过将boost::iequals(存在此问题)替换为仅在循环外调用一次的版本,实现了几倍于100% 的速度提升。
            【解决方案13】:

            如果你想要一些简单的东西,这里有一个宏技术:

            #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 对 this answer 的评论仍然是一个重要的考虑因素,但是,如果您正在处理的不仅仅是 ASCII 字符。

            【讨论】:

            • 当存在完美的解决方案时,我不赞成提供宏——您甚至可以提供这些解决方案。
            • 宏技术意味着在编程中经常使用的代码类型更少。为什么不使用它?否则,为什么还要有宏?
            • 宏是 C 的遗留物,正在努力摆脱。如果要减少输入量,请使用函数或 lambda。 void strtoupper(std::string&amp; x) { std::transform (x.begin(), x.end(), x.begin(), ::toupper); }
            • 不,我不能。不过,Bjarne 在这个话题上的立场已经多次明确。此外,有很多理由不在 C 和 C++ 中使用宏。 x 可能是一个有效的表达式,它恰好编译正确,但由于宏而给出完全虚假的结果。
            • @AquariusPower 我不同意。我还没有看到一个宏不能作为模板或 lambda 做得更好。
            【解决方案14】:

            另一种使用基于范围的for循环和引用变量的方法

            string test = "Hello World";
            for(auto& c : test)
            {
               c = tolower(c);
            }
            
            cout<<test<<endl;
            

            【讨论】:

            • 我猜它不适用于 UTF-8,对吧?
            【解决方案15】:
            // 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/

            【讨论】:

              【解决方案16】:

              代码片段

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

              【讨论】:

                【解决方案17】:

                使用来自fplus 库的fplus::to_lower_case()

                fplus API Search中搜索to_lower_case

                例子:

                fplus::to_lower_case(std::string("ABC")) == std::string("abc");
                

                【讨论】:

                  【解决方案18】:

                  复制,因为它不允许改进答案。谢谢所以


                  string test = "Hello World";
                  for(auto& c : test)
                  {
                     c = tolower(c);
                  }
                  

                  说明:

                  for(auto&amp; c : test) 是一种range-based for loop
                  for (range_declaration:range_expression)@ 987654330@:

                  1. range_declarationauto&amp; c
                    这里auto specifier 用于自动类型推断。所以类型会从变量初始化器中扣除。

                  2. range_expressiontest
                    本例中的范围是字符串test 的字符。

                  字符串test 的字符可通过标识符c 用作for 循环内的引用。

                  【讨论】:

                  • 请说明您是从哪里复制答案的。
                  【解决方案19】:

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

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

                  【讨论】:

                    【解决方案20】:

                    有没有 100% 的时间有效的替代方案?

                    没有

                    在选择小写方法之前,您需要问自己几个问题。

                    1. 字符串是如何编码的?纯ASCII? UTF-8?某种形式的扩展 ASCII 传统编码?
                    2. 小写到底是什么意思?大小写映射规则因语言而异!你想要一些本地化到用户语言环境的东西吗?你想要在你的软件运行的所有系统上表现一致的东西吗?您是否只想将 ASCII 字符小写并通过其他所有内容?
                    3. 有哪些库可用?

                    获得这些问题的答案后,您就可以开始寻找适合您需求的解决方案了。没有一种尺寸适合所有地方的所有人!

                    【讨论】:

                      【解决方案21】:

                      C++ 没有为std::string 实现tolowertoupper 方法,但它可用于char。可以轻松读取字符串的每个字符,将其转换为所需的大小写并将其放回字符串。 不使用任何第三方库的示例代码:

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

                      基于字符的字符串操作:For every character in string

                      【讨论】:

                        【解决方案22】:

                        由于没有一个答案提到即将推出的 Ranges 库,该库自 C++20 起在标准库中可用,目前单独提供 on GitHubrange-v3,我想添加一种方法来执行此转换使用它。

                        就地修改字符串:

                        str |= action::transform([](unsigned char c){ return std::tolower(c); });
                        

                        要生成一个新字符串:

                        auto new_string = original_string
                            | view::transform([](unsigned char c){ return std::tolower(c); });
                        

                        (不要忘记#include &lt;cctype&gt; 和所需的 Ranges 标头。)

                        注意:使用 unsigned char 作为 lambda 的参数是受 cppreference 启发的,它指出:

                        &lt;cctype&gt; 中的所有其他函数一样,如果参数的值既不能表示为unsigned char 也不等于EOF,则std::tolower 的行为是未定义的。为了安全地使用纯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;
                        }
                        

                        【讨论】:

                          【解决方案23】:

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

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

                          【讨论】:

                          • 这是我需要的。我只是将towlower 用于支持 UTF-16 的宽字符。
                          【解决方案24】:

                          试试这个功能:)

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

                          【讨论】:

                          • 这个功能很慢,不应该在实际项目中使用。
                          【解决方案25】:

                          我写了这个简单的辅助函数:

                          #include <locale> // tolower
                          
                          string to_lower(string s) {        
                              for(char &c : s)
                                  c = tolower(c);
                              return s;
                          }
                          

                          用法:

                          string s = "TEST";
                          cout << to_lower("HELLO WORLD"); // output: "hello word"
                          cout << to_lower(s); // won't change the original variable.
                          

                          【讨论】:

                            【解决方案26】:

                            为 ASCII 字符串 to_lower 添加一些可选库,这两个库都是生产级的,并带有微优化,预计会比这里现有的答案更快(TODO:添加基准测试结果)。

                            Facebook 的Folly

                            void toLowerAscii(char* str, size_t length)
                            

                            谷歌的Abseil

                            void AsciiStrToLower(std::string* s);
                            

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 1970-01-01
                              • 2015-01-07
                              • 2016-01-28
                              相关资源
                              最近更新 更多