【问题标题】:Convert a String In C++ To Upper Case将 C++ 中的字符串转换为大写
【发布时间】:2010-10-18 14:59:08
【问题描述】:

如何将字符串转换为大写。我从谷歌搜索中找到的示例只需要处理字符。

【问题讨论】:

    标签: c++ string


    【解决方案1】:
    #include <algorithm>
    #include <string>
    
    std::string str = "Hello World";
    std::transform(str.begin(), str.end(),str.begin(), ::toupper);
    

    【讨论】:

    • 其实toupper()可以实现为宏。这可能会导致问题。
    • 我认为带有 boost.lambda 的 bind(::toupper,construct(_1)) 会非常好。
    • 这种方法适用于 ASCII,但不适用于多字节字符编码,或德语 'ß' 等特殊大小写规则。
    • 我将接受的答案更改为使用 boost 库的答案,因为它更快(在我的非正式测试中),更易于使用,并且没有与此解决方案相关的问题。对于无法使用 boost 的情况,这仍然是一个很好的解决方案。
    • 对于后期读者:从 C++11 开始,我们可以使用 lambda:[](auto c) { return std::toupper(c); }——也许值得更新答案?
    【解决方案2】:

    Boost string algorithms:

    #include <boost/algorithm/string.hpp>
    #include <string>
    
    std::string str = "Hello World";
    
    boost::to_upper(str);
    
    std::string newstr = boost::to_upper_copy<std::string>("Hello World");
    

    【讨论】:

    • 这也有 i18n 的好处,其中::toupper 很可能假定为 ASCII。
    • 这不应该是公认的答案,因为它需要提升,或者应该更改标题。
    • 这似乎在使用 g++ 5.2 -O3 和 Boost 1.58 时表现非常糟糕(比在循环中调用 glibc 的 toupper 差 30 倍。)有一个没有得到的语言环境的 dynamic_cast从每个字符循环中提升出来。看我的回答。从好的方面来说,这可能是对 UTF-8 的正确认识,但减速并不是来自处理 UTF-8;它来自使用dynamic_cast 重新检查每个字符的语言环境。
    • 是的,我要为 to_upper 安装 boost……好主意! 讽刺> :)
    • 我个人不喜欢将 boost 作为“我如何在 C++ 中执行 x?”的答案。因为 boost 根本不是一个轻量级的解决方案。似乎您要么购买 boost 作为一个框架(或 ACE 或 Qt 或 Recusion ToolKit++ 或 ...),要么你不购买。我希望看到语言解决方案。
    【解决方案3】:

    使用 C++11 和 toupper() 的简短解决方案。

    for (auto & c: str) c = toupper(c);
    

    【讨论】:

    • c 不会是const char 类型(来自auto)?如果是这样,您不能将它(因为const 部分)分配给toupper(c) 返回的内容。
    • @PolGraphic: Range - based for 使用容器的 begin() / end() 方法来迭代其内容。 std::basic_string 有一个 const 和一个可变迭代器(分别由 cbegin() 和 begin() 返回,参见std::basic_string::begin),所以 for(:) 使用适当的 (cbegin() 如果 str 被声明为 const, auto =:= const char,否则 begin(),使用 auto =:= char)。
    • 请参阅下面 dirkgently 的分析器,c 需要转换为 unsigned char 才能进行更正。
    • boost 的 to_upper() 似乎比 toupper 更符合 c++ STL 函数。
    • 喜欢这个 - 我和for (auto &amp; c: str) c = (char)toupper(c);一起去了
    【解决方案4】:

    这个问题可以用 SIMD 向量化 用于 ASCII 字符集。


    加速比较:

    在 Core2Duo (Merom) 上使用 x86-64 gcc 5.2 -O3 -march=native 进行初步测试。相同的 120 个字符的字符串(混合小写和非小写 ASCII),在循环中转换 40M 次(没有跨文件内联,因此编译器无法优化或将其中的任何一个提升出循环)。相同的源缓冲区和目标缓冲区,因此没有 malloc 开销或内存/缓存影响:L1 缓存中的数据一直很热,而且我们完全受 CPU 限制。

    • boost::to_upper_copy&lt;char*, std::string&gt;()198.0s。是的,Ubuntu 15.10 上的 Boost 1.58 真的这么慢。我在调试器中对 asm 进行了分析和单步执行,这真的,真的很糟糕:每个字符都会发生一个 locale 变量的 dynamic_cast !!! (dynamic_cast 需要多次调用 strcmp)。 LANG=CLANG=en_CA.UTF-8 会发生这种情况。

      我没有使用除 std::string 之外的 RangeT 进行测试。 Maybe the other form of to_upper_copy 优化得更好,但我认为它总是会为复制空间提供new/malloc 空间,因此更难测试。也许我所做的事情与正常的用例不同,也许通常停止的 g++ 可以将语言环境设置从每个字符循环中提升出来。我从std::string 读取并写入char dstbuf[4096] 的循环对于测试是有意义的。

    • 循环调用 glibc toupper6.67s(不过,不检查 int 结果中是否存在潜在的多字节 UTF-8。这对土耳其语很重要。)

    • ASCII-only 循环:8.79s(以下结果的我的基线版本。)显然,查找表比cmov 更快,无论如何表在 L1 中都是热的。李>
    • 仅 ASCII 自动矢量化:2.51s。 (120 个字符介于最坏情况和最佳情况之间,见下文)
    • 仅 ASCII 手动矢量化:1.35s

    另见this question about toupper() being slow on Windows when a locale is set


    我很震惊 Boost 比其他选项慢一个数量级。我仔细检查了我是否启用了-O3,甚至单步执行 asm 以查看它在做什么。与 clang++ 3.8 的速度几乎完全相同。它在每个字符循环内有巨大的开销。 perf record / report 结果(对于cycles perf 事件)是:

      32.87%  flipcase-clang-  libstdc++.so.6.0.21   [.] _ZNK10__cxxabiv121__vmi_class_type_info12__do_dyncastElNS_17__class_type_info10__sub_kindEPKS1_PKvS4_S6_RNS1_16
      21.90%  flipcase-clang-  libstdc++.so.6.0.21   [.] __dynamic_cast                                                                                                 
      16.06%  flipcase-clang-  libc-2.21.so          [.] __GI___strcmp_ssse3                                                                                            
       8.16%  flipcase-clang-  libstdc++.so.6.0.21   [.] _ZSt9use_facetISt5ctypeIcEERKT_RKSt6locale                                                                     
       7.84%  flipcase-clang-  flipcase-clang-boost  [.] _Z16strtoupper_boostPcRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE                                   
       2.20%  flipcase-clang-  libstdc++.so.6.0.21   [.] strcmp@plt                                                                                                     
       2.15%  flipcase-clang-  libstdc++.so.6.0.21   [.] __dynamic_cast@plt                                                                                             
       2.14%  flipcase-clang-  libstdc++.so.6.0.21   [.] _ZNKSt6locale2id5_M_idEv                                                                                       
       2.11%  flipcase-clang-  libstdc++.so.6.0.21   [.] _ZNKSt6locale2id5_M_idEv@plt                                                                                   
       2.08%  flipcase-clang-  libstdc++.so.6.0.21   [.] _ZNKSt5ctypeIcE10do_toupperEc                                                                                  
       2.03%  flipcase-clang-  flipcase-clang-boost  [.] _ZSt9use_facetISt5ctypeIcEERKT_RKSt6locale@plt                                                                 
       0.08% ...
    

    自动矢量化

    只有在循环之前知道迭代次数时,Gcc 和 clang 才会自动向量化循环。 (即像 strlen 的纯 C 实现这样的搜索循环不会自动矢量化。)

    因此,对于小到足以放入缓存的字符串,我们从首先执行strlen 获得约128 个字符长的字符串的显着加速。对于显式长度的字符串(如 C++ std::string),这不是必需的。

    // char, not int, is essential: otherwise gcc unpacks to vectors of int!  Huge slowdown.
    char ascii_toupper_char(char c) {
        return ('a' <= c && c <= 'z') ? c^0x20 : c;    // ^ autovectorizes to PXOR: runs on more ports than paddb
    }
    
    // gcc can only auto-vectorize loops when the number of iterations is known before the first iteration.  strlen gives us that
    size_t strtoupper_autovec(char *dst, const char *src) {
        size_t len = strlen(src);
        for (size_t i=0 ; i<len ; ++i) {
            dst[i] = ascii_toupper_char(src[i]);  // gcc does the vector range check with psubusb / pcmpeqb instead of pcmpgtb
        }
        return len;
    }
    

    任何体面的 libc 都会有一个高效的strlen,这比一次循环一个字节要快得多,因此单独的矢量化 strlen 和 toupper 循环更快。

    基线:动态检查终止 0 的循环。

    在 Core2 (Merom) 2.4GHz 上进行 40M 次迭代的时间。 gcc 5.2-O3 -march=native。 (Ubuntu 15.10)。 dst != src(所以我们复制了一份),但它们不重叠(也不在附近)。两者都对齐。

    • 15 字符字符串:基线:1.08 秒。自动检测:1.34 秒
    • 16 字符字符串:基线:1.16 秒。自动检测:1.52 秒
    • 127 个字符字符串:基线:8.91 秒。 autovec: 2.98s // 非向量清理有 15 个字符要处理
    • 128 字符字符串:基线:9.00s。自动检测:2.06 秒
    • 129 个字符字符串:基线:9.04 秒。 autovec: 2.07s // 非向量清理有 1 个字符要处理

    有些结果与 clang 有点不同。

    调用函数的微基准循环位于单独的文件中。否则它内联并且strlen() 被提升出循环,并且它运行得更快,尤其是。对于 16 个字符字符串 (0.187s)。

    这具有 gcc 可以为任何架构自动矢量化它的主要优点,但主要缺点是它对于通常常见的小字符串情况较慢。


    因此有很大的加速,但编译器自动矢量化并不能生成出色的代码,尤其是。用于清理最后最多 15 个字符。

    使用 SSE 内在函数进行手动矢量化:

    基于我的case-flip function,它反转了每个字母字符的大小写。它利用了“无符号比较技巧”,您可以在其中通过范围移位对单个无符号比较进行low &lt; a &amp;&amp; a &lt;= high,这样任何小于low 的值都会包装成大于high 的值。 (如果 lowhigh 相距不太远,则此方法有效。)

    SSE 只有一个有符号的 compare-greater,但我们仍然可以使用“unsigned 通过范围移动到有符号范围的底部来比较”技巧:减去'a'+128,因此字母字符的范围从-128到-128+25(-128+'z'-'a')

    请注意,对于 8 位整数,加 128 和减 128 是一回事。进位无处可去,所以它只是异或(无进位加),翻转高位。

    #include <immintrin.h>
    
    __m128i upcase_si128(__m128i src) {
        // The above 2 paragraphs were comments here
        __m128i rangeshift = _mm_sub_epi8(src, _mm_set1_epi8('a'+128));
        __m128i nomodify   = _mm_cmpgt_epi8(rangeshift, _mm_set1_epi8(-128 + 25));  // 0:lower case   -1:anything else (upper case or non-alphabetic).  25 = 'z' - 'a'
    
        __m128i flip  = _mm_andnot_si128(nomodify, _mm_set1_epi8(0x20));            // 0x20:lcase    0:non-lcase
    
        // just mask the XOR-mask so elements are XORed with 0 instead of 0x20
        return          _mm_xor_si128(src, flip);
        // it's easier to xor with 0x20 or 0 than to AND with ~0x20 or 0xFF
    }
    

    鉴于此函数适用于一个向量,我们可以在循环中调用它来处理整个字符串。由于我们已经针对 SSE2,我们可以同时进行向量化的字符串结尾检查。

    我们还可以更好地“清理”在执行 16B 向量之后剩余的最后 15 个字节:大写是幂等的,因此重新处理一些输入字节就可以了。我们对源的最后 16B 进行非对齐加载,并将其存储到与循环中最后 16B 存储重叠的 dest 缓冲区中。

    唯一不起作用的情况是整个字符串低于 16B:即使dst=src,非原子读取-修改-写入与不触摸某些相同字节,并且可以破坏多线程代码。

    为此,我们有一个标量循环,也可以让src 对齐。由于我们不知道终止 0 将在哪里,来自src 的未对齐负载可能会进入下一页并出现段错误。如果我们需要对齐的 16B 块中的任何字节,加载整个对齐的 16B 块总是安全的。

    完整来源:in a github gist

    // FIXME: doesn't always copy the terminating 0.
    // microbenchmarks are for this version of the code (with _mm_store in the loop, instead of storeu, for Merom).
    size_t strtoupper_sse2(char *dst, const char *src_begin) {
        const char *src = src_begin;
        // scalar until the src pointer is aligned
        while ( (0xf & (uintptr_t)src) && *src ) {
            *(dst++) = ascii_toupper(*(src++));
        }
    
        if (!*src)
            return src - src_begin;
    
        // current position (p) is now 16B-aligned, and we're not at the end
        int zero_positions;
        do {
            __m128i sv = _mm_load_si128( (const __m128i*)src );
            // TODO: SSE4.2 PCMPISTRI or PCMPISTRM version to combine the lower-case and '\0' detection?
    
            __m128i nullcheck = _mm_cmpeq_epi8(_mm_setzero_si128(), sv);
            zero_positions = _mm_movemask_epi8(nullcheck);
            // TODO: unroll so the null-byte check takes less overhead
            if (zero_positions)
                break;
    
            __m128i upcased = upcase_si128(sv);   // doing this before the loop break lets gcc realize that the constants are still in registers for the unaligned cleanup version.  But it leads to more wasted insns in the early-out case
    
            _mm_storeu_si128((__m128i*)dst, upcased);
            //_mm_store_si128((__m128i*)dst, upcased);  // for testing on CPUs where storeu is slow
            src += 16;
            dst += 16;
        } while(1);
    
        // handle the last few bytes.  Options: scalar loop, masked store, or unaligned 16B.
        // rewriting some bytes beyond the end of the string would be easy,
        // but doing a non-atomic read-modify-write outside of the string is not safe.
        // Upcasing is idempotent, so unaligned potentially-overlapping is a good option.
    
        unsigned int cleanup_bytes = ffs(zero_positions) - 1;  // excluding the trailing null
        const char* last_byte = src + cleanup_bytes;  // points at the terminating '\0'
    
        // FIXME: copy the terminating 0 when we end at an aligned vector boundary
        // optionally special-case cleanup_bytes == 15: final aligned vector can be used.
        if (cleanup_bytes > 0) {
            if (last_byte - src_begin >= 16) {
                // if src==dest, this load overlaps with the last store:  store-forwarding stall.  Hopefully OOO execution hides it
                __m128i sv = _mm_loadu_si128( (const __m128i*)(last_byte-15) ); // includes the \0
                _mm_storeu_si128((__m128i*)(dst + cleanup_bytes - 15), upcase_si128(sv));
            } else {
                // whole string less than 16B
                // if this is common, try 64b or even 32b cleanup with movq / movd and upcase_si128
    #if 1
                for (unsigned int i = 0 ; i <= cleanup_bytes ; ++i) {
                    dst[i] = ascii_toupper(src[i]);
                }
    #else
                // gcc stupidly auto-vectorizes this, resulting in huge code bloat, but no measurable slowdown because it never runs
                for (int i = cleanup_bytes - 1 ;  i >= 0 ; --i) {
                    dst[i] = ascii_toupper(src[i]);
                }
    #endif
            }
        }
    
        return last_byte - src_begin;
    }
    

    在 Core2 (Merom) 2.4GHz 上进行 40M 次迭代的时间。 gcc 5.2-O3 -march=native。 (Ubuntu 15.10)。 dst != src(所以我们复制了一份),但它们不重叠(也不在附近)。两者都对齐。

    • 15 字符字符串:基线:1.08 秒。自动检测:1.34 秒。手动:1.29s
    • 16 字符字符串:基线:1.16 秒。自动检测:1.52 秒。手动:0.335s
    • 31个字符字符串:手动:0.479s
    • 127 个字符字符串:基线:8.91 秒。自动检测:2.98 秒。手动:0.925s
    • 128 字符字符串:基线:9.00s。自动检测:2.06 秒。手动:0.931s
    • 129 个字符字符串:基线:9.04 秒。自动检测:2.07 秒。手动:1.02s

    (实际上是在循环中与_mm_store 计时,而不是_mm_storeu,因为即使地址对齐,在 Merom 上 storeu 的速度也较慢。在 Nehalem 及更高版本上都很好。我也保留了代码原样现在,而不是修复在某些情况下复制终止 0 的失败,因为我不想重新计时。)

    因此,对于长度超过 16B 的短字符串,这比自动矢量化要快得多。长度小于矢量宽度不存在问题。由于存储转发停顿,它们在就地操作时可能是一个问题。 (但请注意,处理我们自己的输出而不是原始输入仍然可以,因为 toupper 是幂等的)。

    根据周围代码的需求和目标微架构,可以针对不同的用例进行大量调整。让编译器为清理部分发出漂亮的代码是很棘手的。使用 ffs(3)(在 x86 上编译为 bsf 或 tzcnt)似乎很好,但显然需要重新考虑这一点,因为我在写下大部分答案后发现了一个错误(参见 FIXME cmets)。

    可以使用movqmovd 加载/存储来获得更小字符串的向量加速。根据您的用例进行自定义。


    UTF-8:

    我们可以检测我们的向量何时有任何设置了高位的字节,并在这种情况下回退到该向量的标量 utf-8 感知循环。 dst 点可以比src 指针前进不同的量,但是一旦我们回到对齐的src 指针,我们仍然只是对dst 进行未对齐的向量存储。

    对于 UTF-8 文本,但主要由 UTF-8 的 ASCII 子集组成,这可能是件好事:在常见情况下具有高性能且在所有情况下行为正确。但是,当有很多非 ASCII 码时,它可能会比一直停留在标量 UTF-8 感知循环中更糟糕。

    如果不利因素很大,以牺牲其他语言为代价提高英语并不是一个面向未来的决定。


    区域感知:

    在土耳其语言环境 (tr_TR) 中,toupper('i') 的正确结果是 'İ' (U0130),而不是 'I'(纯 ASCII)。有关 tolower() 在 Windows 上运行缓慢的问题,请参阅 Martin Bonner's comments

    我们还可以检查异常列表并回退到那里的标量,例如多字节 UTF8 输入字符。

    有了这么多的复杂性,SSE4.2 PCMPISTRM 或其他东西可能可以一次性完成我们的大量检查。

    【讨论】:

    • 哇,分析得很认真
    【解决方案5】:
    struct convert {
       void operator()(char& c) { c = toupper((unsigned char)c); }
    };
    
    // ... 
    string uc_str;
    for_each(uc_str.begin(), uc_str.end(), convert());
    

    注意:顶级解决方案的几个问题:

    21.5 空终止序列实用程序

    这些头文件的内容应与标准 C 库头文件 [。 ..]

    • 这意味着cctype 成员很可能是不适合在标准算法中直接使用的宏。

    • 同一个例子的另一个问题是它没有强制转换参数或验证这是非负的;这对于签署了普通char 的系统尤其危险。 (原因是:如果这是作为宏实现的,它可能会使用查找表,并且您的参数索引到该表中。负索引将为您提供 UB。)

    【讨论】:

    • 正常的 cctype 成员是宏。我记得读过它们也必须是函数,尽管我没有 C90 标准的副本,也不知道它是否明确说明。
    • 它们必须是 C++ 中的函数——即使 C 允许它们是宏。我同意你关于选角的第二点。最佳解决方案可能会传递负值并导致 UB。这就是我没有投赞成票的原因(但我也没有投反对票):)
    • 不能缺少标准引用:7.4.2.2/1(可怜的 litb,仅引用 C99 TC2 草案),以及荣耀 c++98 标准中的 C++ 17.4.1.2/6。
    • (注意它的脚注:“这不允许提供掩码宏的常见做法.. blah blupp .. 在 C++ 中做到这一点的唯一方法是提供一个外部内联函数.") :)
    • ...这是通过这种诡计实现的:stackoverflow.com/questions/650461/…
    【解决方案6】:
    string StringToUpper(string strToConvert)
    {
       for (std::string::iterator p = strToConvert.begin(); strToConvert.end() != p; ++p)
           *p = toupper(*p);
    
       return p;
    }
    

    或者,

    string StringToUpper(string strToConvert)
    {
        std::transform(strToConvert.begin(), strToConvert.end(), strToConvert.begin(), ::toupper);
    
        return strToConvert;
    }
    

    【讨论】:

    • 如果您无权使用 boost,第二个解决方案可能是您可以获得的最佳解决方案。第一个解决方案的参数后面的星星** 做什么?
    • 我很确定 ** 是在代码语法中尝试使用粗体时留下的拼写错误。
    • 当使用负数调用 toupper 时,此代码会调用未定义的行为。
    【解决方案7】:

    以下对我有用。

    #include <algorithm>
    void  toUpperCase(std::string& str)
    {
        std::transform(str.begin(), str.end(), str.begin(), ::toupper);
    }
    
    int main()
    {
       std::string str = "hello";
       toUpperCase(&str);
    }
    

    【讨论】:

    • 请注意,std::transform 是在 中定义的
    • 是的。这个 #include 是必需的,#include
    • 当使用负数调用 toupper 时,此代码会调用未定义的行为。
    • user648545 给出的答案重复 – -1
    • @PiotrDobrogost 我不知道 user648545 给出的答案。我没有复制那个。当我比较两种方法时,方法签名完全不同,尽管两个函数都使用库函数转换。
    【解决方案8】:

    字符串中有 ASCII 或国际字符吗?

    如果是后一种情况,“大写”就没那么简单了,还要看使用的字母。有两院制和一院制字母表。只有两院字母的大小写字符不同。此外,还有复合字符,例如使用所谓的标题大小写的拉丁大写字母'DZ' (\u01F1 'DZ')。这意味着只有第一个字符 (D) 被更改。

    我建议您查看ICU,以及简单和完整大小写映射之间的区别。这可能会有所帮助:

    http://userguide.icu-project.org/transforms/casemappings

    【讨论】:

    • 或德语 eszet (sp?),看起来像希腊字母 beta,意思是“ss”。没有一个德语字符表示“SS”,它是大写的。德语中的“street”一词在大写时会增加一个字符。
    • 另一种特殊情况是希腊字母 sigma (Σ),它有 两个小写版本,取决于它是否位于单词的末尾 (ς) 或不是 (σ )。然后是特定于语言的规则,例如土耳其语的大小写映射 I↔ı 和 İ↔i。
    • “大写”称为大小写折叠。
    【解决方案9】:

    如果您只使用 ASCII 字符则更快:

    for(i=0;str[i]!=0;i++)
      if(str[i]<='z' && str[i]>='a')
        str[i]+='A'-'a';
    

    请注意,此代码运行速度更快,但仅适用于 ASCII,不是“抽象”解决方案。

    其他 UTF8 字母的扩展版本

    ...
    if(str[i]<='z' && str[i]>='a') //is latin
        str[i]+='A'-'a';
    else if(str[i]<='я' && str[i]>='а') //cyrillic
        str[i]+='Я'-'я'
    else if(str[i]<='ω' && str[i]>='α') //greek
        str[i]+='Ω'-'ω'
    //etc...
    

    如果您需要完整的 UNICODE 解决方案或更传统和抽象的解决方案,请寻求其他答案并使用 C++ 字符串的方法。

    【讨论】:

    • 问题被标记为C++,但您在此处写了C 答案。 (我不是反对者之一。)
    • 我在这里写了一个 C 答案和一个 C++ 答案,因为 C++ 被编写为与 C 源代码完全兼容,因此任何 C 解决方案也是 C++ 正确解决方案
    • 为什么您决定使用 ASCII 码而不是 ' 中包含的字符?
    • 我会考虑使用更多的逻辑代码str[i]+='A'-'a' 而不是仅仅 32。这样的逻辑不仅适用于拉丁语
    • 不碰撞。第二个“а”不是拉丁文,是西里尔文。是完全不同的符号和不同的代码,只是偶然看起来相同。
    【解决方案10】:

    只要你对 ASCII-only 没问题,并且你可以提供一个指向 RW 内存的有效指针,C 中有一个简单且非常有效的单行:

    void strtoupper(char* str)
    { 
        while (*str) *(str++) = toupper((unsigned char)*str);
    }
    

    这对于您想要规范化为相同字符大小写的简单字符串(如 ASCII 标识符)特别有用。然后,您可以使用缓冲区构造 std:string 实例。

    【讨论】:

    • 有人注意到这个答案是针对 c 字符串而不是 std::string
    • 这有一个明显的固有安全漏洞。我不会这样做。
    【解决方案11】:

    使用 lambda。

    std::string s("change my case");
    
    std::locale locale;
    auto to_upper = [&locale] (char ch) { return std::use_facet<std::ctype<char>>(locale).toupper(ch); };
    
    std::transform(s.begin(), s.end(), s.begin(), to_upper);
    

    【讨论】:

    • 拜伦,别担心其他cmets。像你一样用新的(现代)解决方案来回答老问题是完全可以的。
    【解决方案12】:
    //works for ASCII -- no clear advantage over what is already posted...
    
    std::string toupper(const std::string & s)
    {
        std::string ret(s.size(), char());
        for(unsigned int i = 0; i < s.size(); ++i)
            ret[i] = (s[i] <= 'z' && s[i] >= 'a') ? s[i]-('a'-'A') : s[i];
        return ret;
    }
    

    【讨论】:

    • s.size() 是 std::size_t 类型,根据实现,AFAIK 很可能是 unsigned int
    • 我认为没有任何现代实现对 std::string::size 的结果进行签名。鉴于此,无论是语义上还是实际上,都不存在负大小之类的东西,我将使用 size_t 至少是一个 32 位无符号整数。
    • 没有理由不写for (size_t i = 0 ...。也没有充分的理由让它如此难以阅读。这也首先复制字符串,然后循环遍历它。 @Luke 的答案在某些方面更好,除了不利用 'a' 字符常量。
    【解决方案13】:
    #include <string>
    #include <locale>
    
    std::string str = "Hello World!";
    auto & f = std::use_facet<std::ctype<char>>(std::locale());
    f.toupper(str.data(), str.data() + str.size());
    

    这将比使用全局 toupper 函数的所有答案表现更好,并且大概是 boost::to_upper 在下面所做的。

    这是因为 ::toupper 必须查找语言环境 - 因为它可能已被不同的线程更改 - 对于每次调用,而这里只有对 locale() 的调用有这种惩罚。查找语言环境通常需要锁定。

    这也适用于 C++98 后你替换自动,使用新的非常量 str.data(),并添加一个空格来打破模板关闭(“>>”到“>”)像这样:

    std::use_facet<std::ctype<char> > & f = 
        std::use_facet<std::ctype<char> >(std::locale());
    f.toupper(const_cast<char *>(str.data()), str.data() + str.size());
    

    【讨论】:

      【解决方案14】:
      typedef std::string::value_type char_t;
      
      char_t up_char( char_t ch )
      {
          return std::use_facet< std::ctype< char_t > >( std::locale() ).toupper( ch );
      }
      
      std::string toupper( const std::string &src )
      {
          std::string result;
          std::transform( src.begin(), src.end(), std::back_inserter( result ), up_char );
          return result;
      }
      
      const std::string src  = "test test TEST";
      
      std::cout << toupper( src );
      

      【讨论】:

      • 不会推荐 back_inserter,因为您已经知道长度;使用 std::string 结果(src.size()); std::transform(src.begin(), src.end(), result.begin(), up_char);
      • 尽管我确信你知道这一点。
      • @Viktor Sehr, @bayda:我知道这已经 2 岁了,但为什么不两全其美。使用reserveback_inserter(使字符串只复制一次)。 inline std::string to_lower(const std::string &amp;s) { std::string result; result.reserve(s.size()); std::transform(s.begin(), s.end(), std::back_inserter( result ), static_cast&lt;int(*)(int)&gt;(std::tolower)); return result; }
      • 对于那些正在寻找从 Win32 控制台输入代码页进行转换的人:使用 std::locale() 而不是这个:std::locale(std::string(".") + std::to_string(GetConsoleCP()))。在我的情况下,在MSVC 2015 Update 3 下,可执行文件的大小增加了两倍。如果尝试仅使用std::locale() + facet,则在Release 中,可执行文件在+~60KB 上增加,在std::locale with string constructor 的情况下,在+~200KB 上增加。所以要小心。
      【解决方案15】:

      @dirkgentlyanswer 非常鼓舞人心,但我想强调的是,由于如下所示的关注,

      与 中的所有其他函数一样,如果参数的值既不能表示为 unsigned char 也不等于 EOF,则 std::toupper 的行为是未定义的。为了安全地使用纯字符(或有符号字符)这些函数,应首先将参数转换为无符号字符
      参考std::toupper

      由于标准没有指定普通char是有符号还是无符号[1]std::toupper 的正确用法应该是:

      #include <algorithm>
      #include <cctype>
      #include <iostream>
      #include <iterator>
      #include <string>
      
      void ToUpper(std::string& input)
      {
          std::for_each(std::begin(input), std::end(input), [](char& c) {
              c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
          });
      }
      
      int main()
      {
          std::string s{ "Hello world!" };
          std::cout << s << std::endl;
          ::ToUpper(s);
          std::cout << s << std::endl;
      
          return 0;
      }
      

      输出:

      Hello world!
      HELLO WORLD!
      

      【讨论】:

        【解决方案16】:
        std::string value;
        for (std::string::iterator p = value.begin(); value.end() != p; ++p)
            *p = toupper(*p);
        

        【讨论】:

        • 当使用负数调用 toupper 时,此代码会调用未定义的行为。
        【解决方案17】:
        std::string str = "STriNg oF mIxID CasE lETteRS"
        

        C++ 11

        • 使用 for_each

          std::for_each(str.begin(), str.end(), [](char &amp; c){ c = ::toupper(c); });

        • 使用变换

          std::transform(str.begin(), str.end(), str.begin(), ::toupper);

        C++(仅限 Winodws)

        _strupr_s(str, str.length());
        

        C++(使用 Boost 库)

        boost::to_upper_copy(str)
        

        【讨论】:

          【解决方案18】:

          尝试toupper() 函数 (#include &lt;ctype.h&gt;)。它接受字符作为参数,字符串由字符组成,因此您必须遍历每个单独的字符,这些字符放在一起构成字符串

          【讨论】:

          • 当使用负数调用 toupper 时,此建议会调用未定义的行为。您应该向unsigned char 提及必要的演员表。
          【解决方案19】:

          这是最新的 C++11 代码

          std::string cmd = "Hello World";
          for_each(cmd.begin(), cmd.end(), [](char& in){ in = ::toupper(in); });
          

          【讨论】:

          • 当使用负数调用 toupper 时,此代码会调用未定义的行为。
          【解决方案20】:

          使用 Boost.Text,它适用于 Unicode 文本

          boost::text::text t = "Hello World";
          boost::text::text uppered;
          boost::text::to_title(t, std::inserter(uppered, uppered.end()));
          std::string newstr = uppered.extract();
          

          【讨论】:

            【解决方案21】:

            如果你只想大写,试试这个功能。

            #include <iostream>
            
            
            using namespace std;
            
            string upper(string text){
                string upperCase;
                for(int it : text){
                    if(it>96&&it<123){
                        upperCase += char(it-32);
                    }else{
                        upperCase += char(it);
                    }
                }
                return upperCase;
            }
            
            int main() {
                string text = "^_abcdfghopqrvmwxyz{|}";
                cout<<text<<"/";
                text = upper(text);
                cout<<text;
                return 0;
            }
            

            Error: Range-based 'for' loops are not allowed in C++98 mode

            【讨论】:

              【解决方案22】:

              不确定是否有内置函数。试试这个:

              包括 ctype.h 或 cctype 库以及 stdlib.h 作为预处理器指令的一部分。

              string StringToUpper(string strToConvert)
              {//change each element of the string to upper case
                 for(unsigned int i=0;i<strToConvert.length();i++)
                 {
                    strToConvert[i] = toupper(strToConvert[i]);
                 }
                 return strToConvert;//return the converted string
              }
              
              string StringToLower(string strToConvert)
              {//change each element of the string to lower case
                 for(unsigned int i=0;i<strToConvert.length();i++)
                 {
                    strToConvert[i] = tolower(strToConvert[i]);
                 }
                 return strToConvert;//return the converted string
              }
              

              【讨论】:

              • .length() 不是 'unsigned int' 类型
              • 当使用负数调用 toupper 时,此代码会调用未定义的行为。
              【解决方案23】:

              我的解决方案(清除 alpha 的第 6 位):

              #include <ctype.h>
              
              inline void toupper(char* str)
              {
                  while (str[i]) {
                      if (islower(str[i]))
                          str[i] &= ~32; // Clear bit 6 as it is what differs (32) between Upper and Lowercases
                      i++;
                  }
              }
              

              【讨论】:

              • 当使用负数调用 toupper 时,此代码会调用未定义的行为。
              • 否...请在投票前检查您是否正确。 Islower 仅适用于非负值...
              【解决方案24】:

              基于Kyle_the_hacker's -----> answer 和我的临时演员。

              Ubuntu

              在终端 列出所有语言环境
              locale -a

              安装所有语言环境
              sudo apt-get install -y locales locales-all

              编译main.cpp
              $ g++ main.cpp

              运行编译好的程序
              $ ./a.out

              结果

              Zoë Saldaña played in La maldición del padre Cardona. ëèñ αω óóChloë
              Zoë Saldaña played in La maldición del padre Cardona. ëèñ αω óóChloë
              ZOË SALDAÑA PLAYED IN LA MALDICIÓN DEL PADRE CARDONA. ËÈÑ ΑΩ ÓÓCHLOË
              ZOË SALDAÑA PLAYED IN LA MALDICIÓN DEL PADRE CARDONA. ËÈÑ ΑΩ ÓÓCHLOË
              zoë saldaña played in la maldición del padre cardona. ëèñ αω óóchloë
              zoë saldaña played in la maldición del padre cardona. ëèñ αω óóchloë
              

              窗口

              在 cmd 中运行 VCVARS 开发者工具
              "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"

              编译main.cpp
              &gt; cl /EHa main.cpp /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /std:c++17 /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /MTd

              Compilador de optimización de C/C++ de Microsoft (R) versión 19.27.29111 para x64
              (C) Microsoft Corporation. Todos los derechos reservados.
              
              main.cpp
              Microsoft (R) Incremental Linker Version 14.27.29111.0
              Copyright (C) Microsoft Corporation.  All rights reserved.
              
              /out:main.exe
              main.obj
              kernel32.lib
              user32.lib
              gdi32.lib
              winspool.lib
              comdlg32.lib
              advapi32.lib
              shell32.lib
              ole32.lib
              oleaut32.lib
              uuid.lib
              odbc32.lib
              odbccp32.lib
              

              运行 main.exe
              &gt;main.exe

              结果

              Zoë Saldaña played in La maldición del padre Cardona. ëèñ αω óóChloë
              Zoë Saldaña played in La maldición del padre Cardona. ëèñ αω óóChloë
              ZOË SALDAÑA PLAYED IN LA MALDICIÓN DEL PADRE CARDONA. ËÈÑ ΑΩ ÓÓCHLOË
              ZOË SALDAÑA PLAYED IN LA MALDICIÓN DEL PADRE CARDONA. ËÈÑ ΑΩ ÓÓCHLOË
              zoë saldaña played in la maldición del padre cardona. ëèñ αω óóchloë
              zoë saldaña played in la maldición del padre cardona. ëèñ αω óóchloë
              

              代码 - main.cpp

              此代码仅在 Windows x64 和 Ubuntu Linux x64 上测试过。

              /*
               * Filename: c:\Users\x\Cpp\main.cpp
               * Path: c:\Users\x\Cpp
               * Filename: /home/x/Cpp/main.cpp
               * Path: /home/x/Cpp
               * Created Date: Saturday, October 17th 2020, 10:43:31 pm
               * Author: Joma
               *
               * No Copyright 2020
               */
              
              
              #include <iostream>
              #include <set>
              #include <string>
              #include <locale>
              
              // WINDOWS
              #if (_WIN32)
              #include <Windows.h>
              #include <conio.h>
              #define WINDOWS_PLATFORM 1
              #define DLLCALL STDCALL
              #define DLLIMPORT _declspec(dllimport)
              #define DLLEXPORT _declspec(dllexport)
              #define DLLPRIVATE
              #define NOMINMAX
              
              //EMSCRIPTEN
              #elif defined(__EMSCRIPTEN__)
              #include <emscripten/emscripten.h>
              #include <emscripten/bind.h>
              #include <unistd.h>
              #include <termios.h>
              #define EMSCRIPTEN_PLATFORM 1
              #define DLLCALL
              #define DLLIMPORT
              #define DLLEXPORT __attribute__((visibility("default")))
              #define DLLPRIVATE __attribute__((visibility("hidden")))
              
              // LINUX - Ubuntu, Fedora, , Centos, Debian, RedHat
              #elif (__LINUX__ || __gnu_linux__ || __linux__ || __linux || linux)
              #define LINUX_PLATFORM 1
              #include <unistd.h>
              #include <termios.h>
              #define DLLCALL CDECL
              #define DLLIMPORT
              #define DLLEXPORT __attribute__((visibility("default")))
              #define DLLPRIVATE __attribute__((visibility("hidden")))
              #define CoTaskMemAlloc(p) malloc(p)
              #define CoTaskMemFree(p) free(p)
              
              //ANDROID
              #elif (__ANDROID__ || ANDROID)
              #define ANDROID_PLATFORM 1
              #define DLLCALL
              #define DLLIMPORT
              #define DLLEXPORT __attribute__((visibility("default")))
              #define DLLPRIVATE __attribute__((visibility("hidden")))
              
              //MACOS
              #elif defined(__APPLE__)
              #include <unistd.h>
              #include <termios.h>
              #define DLLCALL
              #define DLLIMPORT
              #define DLLEXPORT __attribute__((visibility("default")))
              #define DLLPRIVATE __attribute__((visibility("hidden")))
              #include "TargetConditionals.h"
              #if TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
              #define IOS_SIMULATOR_PLATFORM 1
              #elif TARGET_OS_IPHONE
              #define IOS_PLATFORM 1
              #elif TARGET_OS_MAC
              #define MACOS_PLATFORM 1
              #else
              
              #endif
              
              #endif
              
              
              
              typedef std::string String;
              typedef std::wstring WString;
              
              #define EMPTY_STRING u8""s
              #define EMPTY_WSTRING L""s
              
              using namespace std::literals::string_literals;
              
              class Strings
              {
              public:
                  static String WideStringToString(const WString& wstr)
                  {
                      if (wstr.empty())
                      {
                          return String();
                      }
                      size_t pos;
                      size_t begin = 0;
                      String ret;
              
              #if WINDOWS_PLATFORM
                      int size;
                      pos = wstr.find(static_cast<wchar_t>(0), begin);
                      while (pos != WString::npos && begin < wstr.length())
                      {
                          WString segment = WString(&wstr[begin], pos - begin);
                          size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &segment[0], segment.size(), NULL, 0, NULL, NULL);
                          String converted = String(size, 0);
                          WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &segment[0], segment.size(), &converted[0], converted.size(), NULL, NULL);
                          ret.append(converted);
                          ret.append({ 0 });
                          begin = pos + 1;
                          pos = wstr.find(static_cast<wchar_t>(0), begin);
                      }
                      if (begin <= wstr.length())
                      {
                          WString segment = WString(&wstr[begin], wstr.length() - begin);
                          size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &segment[0], segment.size(), NULL, 0, NULL, NULL);
                          String converted = String(size, 0);
                          WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &segment[0], segment.size(), &converted[0], converted.size(), NULL, NULL);
                          ret.append(converted);
                      }
              #elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
                      size_t size;
                      pos = wstr.find(static_cast<wchar_t>(0), begin);
                      while (pos != WString::npos && begin < wstr.length())
                      {
                          WString segment = WString(&wstr[begin], pos - begin);
                          size = wcstombs(nullptr, segment.c_str(), 0);
                          String converted = String(size, 0);
                          wcstombs(&converted[0], segment.c_str(), converted.size());
                          ret.append(converted);
                          ret.append({ 0 });
                          begin = pos + 1;
                          pos = wstr.find(static_cast<wchar_t>(0), begin);
                      }
                      if (begin <= wstr.length())
                      {
                          WString segment = WString(&wstr[begin], wstr.length() - begin);
                          size = wcstombs(nullptr, segment.c_str(), 0);
                          String converted = String(size, 0);
                          wcstombs(&converted[0], segment.c_str(), converted.size());
                          ret.append(converted);
                      }
              #else
                      static_assert(false, "Unknown Platform");
              #endif
                      return ret;
                  }
              
                  static WString StringToWideString(const String& str)
                  {
                      if (str.empty())
                      {
                          return WString();
                      }
              
                      size_t pos;
                      size_t begin = 0;
                      WString ret;
              #ifdef WINDOWS_PLATFORM
                      int size = 0;
                      pos = str.find(static_cast<char>(0), begin);
                      while (pos != std::string::npos) {
                          std::string segment = std::string(&str[begin], pos - begin);
                          std::wstring converted = std::wstring(segment.size() + 1, 0);
                          size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, &segment[0], segment.size(), &converted[0], converted.length());
                          converted.resize(size);
                          ret.append(converted);
                          ret.append({ 0 });
                          begin = pos + 1;
                          pos = str.find(static_cast<char>(0), begin);
                      }
                      if (begin < str.length()) {
                          std::string segment = std::string(&str[begin], str.length() - begin);
                          std::wstring converted = std::wstring(segment.size() + 1, 0);
                          size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, segment.c_str(), segment.size(), &converted[0], converted.length());
                          converted.resize(size);
                          ret.append(converted);
                      }
              
              #elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
                      size_t size;
                      pos = str.find(static_cast<char>(0), begin);
                      while (pos != String::npos)
                      {
                          String segment = String(&str[begin], pos - begin);
                          WString converted = WString(segment.size(), 0);
                          size = mbstowcs(&converted[0], &segment[0], converted.size());
                          converted.resize(size);
                          ret.append(converted);
                          ret.append({ 0 });
                          begin = pos + 1;
                          pos = str.find(static_cast<char>(0), begin);
                      }
                      if (begin < str.length())
                      {
                          String segment = String(&str[begin], str.length() - begin);
                          WString converted = WString(segment.size(), 0);
                          size = mbstowcs(&converted[0], &segment[0], converted.size());
                          converted.resize(size);
                          ret.append(converted);
                      }
              #else
                      static_assert(false, "Unknown Platform");
              #endif
                      return ret;
                  }
              
              
                  static WString ToUpper(const WString& data)
                  {
                      WString result = data;
                      auto& f = std::use_facet<std::ctype<wchar_t>>(std::locale());
              
                      f.toupper(&result[0], &result[0] + result.size());
                      return result;
                  }
              
                  static String  ToUpper(const String& data)
                  {
                      return WideStringToString(ToUpper(StringToWideString(data)));
                  }
              
                  static WString ToLower(const WString& data)
                  {
                      WString result = data;
                      auto& f = std::use_facet<std::ctype<wchar_t>>(std::locale());
                      f.tolower(&result[0], &result[0] + result.size());
                      return result;
                  }
              
                  static String ToLower(const String& data)
                  {
                      return WideStringToString(ToLower(StringToWideString(data)));
                  }
              
              };
              
              enum class ConsoleTextStyle
              {
                  DEFAULT = 0,
                  BOLD = 1,
                  FAINT = 2,
                  ITALIC = 3,
                  UNDERLINE = 4,
                  SLOW_BLINK = 5,
                  RAPID_BLINK = 6,
                  REVERSE = 7,
              };
              
              enum class ConsoleForeground
              {
                  DEFAULT = 39,
                  BLACK = 30,
                  DARK_RED = 31,
                  DARK_GREEN = 32,
                  DARK_YELLOW = 33,
                  DARK_BLUE = 34,
                  DARK_MAGENTA = 35,
                  DARK_CYAN = 36,
                  GRAY = 37,
                  DARK_GRAY = 90,
                  RED = 91,
                  GREEN = 92,
                  YELLOW = 93,
                  BLUE = 94,
                  MAGENTA = 95,
                  CYAN = 96,
                  WHITE = 97
              };
              
              enum class ConsoleBackground
              {
                  DEFAULT = 49,
                  BLACK = 40,
                  DARK_RED = 41,
                  DARK_GREEN = 42,
                  DARK_YELLOW = 43,
                  DARK_BLUE = 44,
                  DARK_MAGENTA = 45,
                  DARK_CYAN = 46,
                  GRAY = 47,
                  DARK_GRAY = 100,
                  RED = 101,
                  GREEN = 102,
                  YELLOW = 103,
                  BLUE = 104,
                  MAGENTA = 105,
                  CYAN = 106,
                  WHITE = 107
              };
              
              class Console
              {
              private:
                  static void EnableVirtualTermimalProcessing()
                  {
              #if defined WINDOWS_PLATFORM
                      HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
                      DWORD dwMode = 0;
                      GetConsoleMode(hOut, &dwMode);
                      if (!(dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING))
                      {
                          dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
                          SetConsoleMode(hOut, dwMode);
                      }
              #endif
                  }
              
                  static void ResetTerminalFormat()
                  {
                      std::cout << u8"\033[0m";
                  }
              
                  static void SetVirtualTerminalFormat(ConsoleForeground foreground, ConsoleBackground background, std::set<ConsoleTextStyle> styles)
                  {
                      String format = u8"\033[";
                      format.append(std::to_string(static_cast<int>(foreground)));
                      format.append(u8";");
                      format.append(std::to_string(static_cast<int>(background)));
                      if (styles.size() > 0)
                      {
                          for (auto it = styles.begin(); it != styles.end(); ++it)
                          {
                              format.append(u8";");
                              format.append(std::to_string(static_cast<int>(*it)));
                          }
                      }
                      format.append(u8"m");
                      std::cout << format;
                  }
              public:
                  static void Clear()
                  {
              
              #ifdef WINDOWS_PLATFORM
                      std::system(u8"cls");
              #elif LINUX_PLATFORM || defined MACOS_PLATFORM
                      std::system(u8"clear");
              #elif EMSCRIPTEN_PLATFORM
                      emscripten::val::global()["console"].call<void>(u8"clear");
              #else
                      static_assert(false, "Unknown Platform");
              #endif
                  }
              
                  static void Write(const String& s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
                  {
              #ifndef EMSCRIPTEN_PLATFORM
                      EnableVirtualTermimalProcessing();
                      SetVirtualTerminalFormat(foreground, background, styles);
              #endif
                      String str = s;
              #ifdef WINDOWS_PLATFORM
                      WString unicode = Strings::StringToWideString(str);
                      WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), static_cast<DWORD>(unicode.length()), nullptr, nullptr);
              #elif defined LINUX_PLATFORM || defined MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
                      std::cout << str;
              #else
                      static_assert(false, "Unknown Platform");
              #endif
              
              #ifndef EMSCRIPTEN_PLATFORM
                      ResetTerminalFormat();
              #endif
                  }
              
                  static void WriteLine(const String& s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
                  {
                      Write(s, foreground, background, styles);
                      std::cout << std::endl;
                  }
              
                  static void Write(const WString& s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
                  {
              #ifndef EMSCRIPTEN_PLATFORM
                      EnableVirtualTermimalProcessing();
                      SetVirtualTerminalFormat(foreground, background, styles);
              #endif
                      WString str = s;
              
              #ifdef WINDOWS_PLATFORM
                      WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), str.c_str(), static_cast<DWORD>(str.length()), nullptr, nullptr);
              #elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
                      std::cout << Strings::WideStringToString(str);
              #else
                      static_assert(false, "Unknown Platform");
              #endif
              
              #ifndef EMSCRIPTEN_PLATFORM
                      ResetTerminalFormat();
              #endif
                  }
              
                  static void WriteLine(const WString& s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
                  {
                      Write(s, foreground, background, styles);
                      std::cout << std::endl;
                  }
              
                  static void WriteLine()
                  {
                      std::cout << std::endl;
                  }
              
                  static void Pause()
                  {
                      char c;
                      do
                      {
                          c = getchar();
                          std::cout << "Press Key " << std::endl;
                      } while (c != 64);
                      std::cout << "KeyPressed" << std::endl;
                  }
              
                  static int PauseAny(bool printWhenPressed = false, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
                  {
                      int ch;
              #ifdef WINDOWS_PLATFORM
                      ch = _getch();
              #elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
                      struct termios oldt, newt;
                      tcgetattr(STDIN_FILENO, &oldt);
                      newt = oldt;
                      newt.c_lflag &= ~(ICANON | ECHO);
                      tcsetattr(STDIN_FILENO, TCSANOW, &newt);
                      ch = getchar();
                      tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
              #else
                      static_assert(false, "Unknown Platform");
              #endif
                      if (printWhenPressed)
                      {
                          Console::Write(String(1, ch), foreground, background, styles);
                      }
                      return ch;
                  }
              };
              
              
              
              int main()
              {
                  std::locale::global(std::locale(u8"en_US.UTF-8"));
                  String dataStr = u8"Zoë Saldaña played in La maldición del padre Cardona. ëèñ αω óóChloë";
                  WString dataWStr = L"Zoë Saldaña played in La maldición del padre Cardona. ëèñ αω óóChloë";
                  std::string locale = u8"";
                  //std::string locale = u8"de_DE.UTF-8";
                  //std::string locale = u8"en_US.UTF-8";
                  Console::WriteLine(dataStr);
                  Console::WriteLine(dataWStr);
                  dataStr = Strings::ToUpper(dataStr);
                  dataWStr = Strings::ToUpper(dataWStr);
                  Console::WriteLine(dataStr);
                  Console::WriteLine(dataWStr);
                  dataStr = Strings::ToLower(dataStr);
                  dataWStr = Strings::ToLower(dataWStr);
                  Console::WriteLine(dataStr);
                  Console::WriteLine(dataWStr);
                  
                  
                  Console::WriteLine(u8"Press any key to exit"s, ConsoleForeground::DARK_GRAY);
                  Console::PauseAny();
              
                  return 0;
              }
              
              

              【讨论】:

                【解决方案25】:
                //Since I work on a MAC, and Windows methods mentioned do not work for me, I //just built this quick method.
                
                
                string str; 
                    str = "This String Will Print Out in all CAPS";
                    int len = str.size(); 
                    char b;
                
                for (int i = 0; i < len; i++){
                    b = str[i]; 
                    b = toupper(b); 
                   // b = to lower(b); //alternately 
                     str[i] = b;    
                }
                    
                
                cout<<str;
                

                【讨论】:

                • 虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。
                • 确实如此。谢谢你。将来我会更好地在我的代码中进行注释。
                【解决方案26】:

                此页面上的所有这些解决方案都比他们需要的更难。

                这样做

                RegName = "SomE StRing That you wAnt ConvErTed";
                NameLength = RegName.Size();
                for (int forLoop = 0; forLoop < NameLength; ++forLoop)
                {
                     RegName[forLoop] = tolower(RegName[forLoop]);
                }
                

                RegName 是您的string。 获取您的字符串大小不要使用string.size() 作为您的实际测试人员,非常混乱和 可能会导致问题。 然后。最基本的for 循环。

                记住字符串大小也会返回分隔符,所以在循环测试中使用

                输出将是: 一些你想要转换的字符串

                【讨论】:

                • 我看不出这比 boost::toupper 解决方案更简单。你能详细说明一下吗?
                • 已经有很多简单的tolower 循环,而且大多数都使用标准的循环变量名称,例如i,而不是奇怪的forLoop
                【解决方案27】:

                不使用任何库:

                std::string YourClass::Uppercase(const std::string & Text)
                {
                    std::string UppperCaseString;
                    UppperCaseString.reserve(Text.size());
                    for (std::string::const_iterator it=Text.begin(); it<Text.end(); ++it)
                    {
                        UppperCaseString.push_back(((0x60 < *it) && (*it < 0x7B)) ? (*it - static_cast<char>(0x20)) : *it);
                    }
                    return UppperCaseString;
                }
                

                【讨论】:

                • 以上代码仅适用于 ASCII 兼容的编码。问题和您的回答都没有提到这个限制。其中一个应该。
                【解决方案28】:

                如果您只关心 8 位字符(除了 Milan Babuškov 之外的所有其他答案也都假设),您可以通过在编译时使用元编程生成查找表来获得最快的速度。在 ideone.com 上,它的运行速度比库函数快 7 倍,比手写版本快 3 倍 (http://ideone.com/sb1Rup)。它也可以通过特征进行定制,不会减慢速度。

                template<int ...Is>
                struct IntVector{
                using Type = IntVector<Is...>;
                };
                
                template<typename T_Vector, int I_New>
                struct PushFront;
                template<int ...Is, int I_New>
                struct PushFront<IntVector<Is...>,I_New> : IntVector<I_New,Is...>{};
                
                template<int I_Size, typename T_Vector = IntVector<>>
                struct Iota : Iota< I_Size-1, typename PushFront<T_Vector,I_Size-1>::Type> {};
                template<typename T_Vector>
                struct Iota<0,T_Vector> : T_Vector{};
                
                template<char C_In>
                struct ToUpperTraits {
                    enum { value = (C_In >= 'a' && C_In <='z') ? C_In - ('a'-'A'):C_In };
                };
                
                template<typename T>
                struct TableToUpper;
                template<int ...Is>
                struct TableToUpper<IntVector<Is...>>{
                    static char at(const char in){
                        static const char table[] = {ToUpperTraits<Is>::value...};
                        return table[in];
                    }
                };
                
                int tableToUpper(const char c){
                    using Table = TableToUpper<typename Iota<256>::Type>;
                    return Table::at(c);
                }
                

                用例:

                std::transform(in.begin(),in.end(),out.begin(),tableToUpper);
                

                对于它的工作原理的深入(多页)描述允许我无耻地插入我的博客:http://metaporky.blogspot.de/2014/07/part-4-generating-look-up-tables-at.html

                【讨论】:

                  【解决方案29】:
                  template<size_t size>
                  char* toupper(char (&dst)[size], const char* src) {
                      // generate mapping table once
                      static char maptable[256];
                      static bool mapped;
                      if (!mapped) {
                          for (char c = 0; c < 256; c++) {
                              if (c >= 'a' && c <= 'z')
                                  maptable[c] = c & 0xdf;
                              else
                                  maptable[c] = c;
                          }
                          mapped = true;
                      }
                  
                      // use mapping table to quickly transform text
                      for (int i = 0; *src && i < size; i++) {
                          dst[i] = maptable[*(src++)];
                      }
                      return dst;
                  }
                  

                  【讨论】:

                    【解决方案30】:

                    这个c++函数总是返回大写字符串...

                    #include <locale> 
                    #include <string>
                    using namespace std; 
                    string toUpper (string str){
                        locale loc; 
                        string n; 
                        for (string::size_type i=0; i<str.length(); ++i)
                            n += toupper(str[i], loc);
                        return n;
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 2012-01-08
                      • 2013-08-02
                      • 1970-01-01
                      • 2016-01-10
                      • 2021-06-11
                      • 2014-06-18
                      • 2018-09-16
                      • 1970-01-01
                      相关资源
                      最近更新 更多