将C ++中的字符串转换为大写字母

时间:2009-04-09 17:38:24

标签: c++ string

如何将字符串转换为大写字母。我通过谷歌搜索找到的例子只需处理字符。

32 个答案:

答案 0 :(得分:447)

#include <algorithm>
#include <string>

std::string str = "Hello World";
std::transform(str.begin(), str.end(),str.begin(), ::toupper);

答案 1 :(得分:200)

提升字符串算法:

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

答案 2 :(得分:78)

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

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

答案 3 :(得分:27)

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库标题&lt; ctype.h&gt;,&lt; wctype.h&gt;,&lt; string.h&gt;,&lt; wchar.h&gt;和&lt; stdlib相同.H&GT; [...]

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

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

答案 4 :(得分:20)

字符串中是否包含ASCII或国际字符?

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

我建议您研究ICU,以及简单和完整案例映射之间的区别。这可能会有所帮助:

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

答案 5 :(得分:18)

对于ASCII字符集,此问题可以使用SIMD 进行矢量化。

加速比较:

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

  • boost::to_upper_copy<char*, std::string>() 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 toupper 6.67s (不检查int结果是否有潜在的多字节UTF-8。这对土耳其语很重要。 )

  • 仅限ASCII的循环: 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循环更快。

Baseline:一个循环检查终止0的循环。

在Core2(Merom)2.4GHz上进行40M迭代的时间。 gcc 5.2 -O3 -march=native。 (Ubuntu 15.10)。 dst != src(所以我们制作副本),但它们不重叠(并且不在附近)。两者都是一致的。

  • 15 char string:baseline:1.08s。 autovec:1.34s
  • 16 char string:baseline:1.16s。 autovec:1.52s
  • 127 char string:baseline:8.91s。 autovec:2.98s //非向量清理有15个字符要处理
  • 128 char string:baseline:9.00s。 autovec:2.06s
  • 129 char string:baseline:9.04s。 autovec:2.07s //非向量清理有1个要处理的字符

某些结果与clang有点不同。

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

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

所以有很大的加速,但编译器自动矢量化并不能创造出优秀的代码,尤其是用于清除最后15个字符。

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

根据我的case-flip function反转每个字母字符的大小写。它利用了&#34;无符号比较技巧&#34;,你可以通过范围转换对low < a && a <= high进行单个无符号比较,这样任何小于low的值都会包含一个& #39; s大于high。 (如果lowhigh距离太远,则此方法有效。)

SSE只有一个签名的比较更大,但我们仍然可以使用&#34; unsigned 比较&#34;通过范围转换到有符号范围的底部的技巧:减去&#39; + = 128,因此字母字符的范围从-128到-128 + 25(-128 +&#39; z&#39; - &#39;一个&#39)

请注意,对于8位整数,添加128和减去128是相同的。随身携带无处可去,所以它只是xor(无负载添加),翻转高位。

#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,因此我们可以同时进行矢量化字符串结束检查。

我们也可以做更好的清理&#34;在执行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 char string:baseline:1.08s。 autovec:1.34s。手册:1.29s
  • 16 char string:baseline:1.16s。 autovec:1.52s。手册:0.335s
  • 31 char string:manual:0.479s
  • 127 char string:baseline:8.91s。 autovec:2.98s。手册:0.925s
  • 128 char string:baseline:9.00s。 autovec:2.06s。手册:0.931s
  • 129 char string:baseline:9.04s。 autovec:2.07s。手册:1.02s

(实际上在循环中与_mm_store进行了对时,而不是_mm_storeu,因为即使地址已对齐,因此即使地址对齐,storeu也会慢一些。在Nehalem以及之后它很好。我&#39 ; ve还暂时保留了代码,而不是修复在某些情况下复制终止0的失败,因为我不想重新计算所有内容。)

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

根据周围代码的需要以及目标微体系结构,针对不同的用例调整此问题的范围很广。让编译器为清理部分发出漂亮的代码是很棘手的。使用ffs(3)(在x86上编译为bsf或tzcnt)似乎很好,但显然这个位需要重新思考,因为我在写完大部分答案之后发现了一个错误(参见FIXME评论)。 / p>

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

UTF-8:

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

对于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或其他东西可以一次性完成我们的很多检查。

答案 6 :(得分:18)

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

答案 7 :(得分:15)

如果仅使用ASCII字符,则越快

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

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

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

答案 8 :(得分:12)

以下适用于我。

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

int main()
{
   std::string str = "hello";
   toUpperCase(&str);
}

答案 9 :(得分:11)

使用lambda。

std::string s("change my case");

auto to_upper = [] (char_t ch) { return std::use_facet<std::ctype<char_t>>(std::locale()).toupper(ch); };

std::transform(s.begin(), s.end(), s.begin(), to_upper);

答案 10 :(得分:10)

只要您使用纯ASCII并且可以提供有效的RW内存指针,C语言中就会有一个简单且非常有效的单线程:

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

这对于像ASCII标识符这样的简单字符串尤其有用,您希望将其标准化为相同的字符大小写。然后,您可以使用缓冲区构造std:string实例。

答案 11 :(得分:10)

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

答案 12 :(得分:9)

#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()的调用才会有这种惩罚。查找语言环境通常需要锁定。

在更换auto,使用新的非const str.data()并添加空格以打破模板关闭后,这也适用于C ++ 98(&#34;&gt;&gt;&# 34;到&#34;&gt;&gt;&#34;)像这样:

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

答案 13 :(得分:7)

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

答案 14 :(得分:4)

std::string value;
for (std::string::iterator p = value.begin(); value.end() != p; ++p)
    *p = toupper(*p);

答案 15 :(得分:2)

answer中的@dirkgently很有启发性,但是我想强调一下,由于如下所示,

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

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 :(得分:2)

以下是使用C ++ 11的最新代码

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

答案 17 :(得分:2)

尝试toupper()函数(#include <ctype.h>)。它接受字符作为参数,字符串由字符组成,因此你必须迭代每个单独的字符,当它们放在一起构成字符串时

答案 18 :(得分:1)

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

答案 19 :(得分:0)

我的解决方案(清除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++;
    }
}

答案 20 :(得分:0)

不确定是否有内置功能。试试这个:

包含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
}

答案 21 :(得分:0)

我的解决方案

基于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ë
VSCODE的

WSL Ubuntu Linux - WSL from VSCODE

WSL Ubuntu Linux - WSL

Ubuntu VM Ubuntu VM

Windows

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

编译main.cpp
> 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
>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ë

Windows

代码-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 <locale>
#include <string>
#include <algorithm>
#include <set>
#include <cstdlib>
#include <clocale>

#if defined(_WIN32)
#define WINDOWSLIB 1
#define DLLCALL STDCALL
#define DLLIMPORT _declspec(dllimport)
#define DLLEXPORT _declspec(dllexport)
#define DLLPRIVATE

#define NOMINMAX
#include <Windows.h>
#include <objbase.h>
#include <filesystem>
#include <intrin.h>
#include <conio.h>

#elif defined(__ANDROID__) || defined(ANDROID) //Android
#define ANDROIDLIB 1
#define DLLCALL CDECL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))

#elif defined(__APPLE__) //iOS, Mac OS
#define MACOSLIB 1
#define DLLCALL CDECL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))

#elif defined(__LINUX__) || defined(__gnu_linux__) || defined(__linux__) || defined(__linux) || defined(linux) //_Ubuntu - Fedora - Centos - RedHat
#define LINUXLIB 1
#include <cpuid.h>
#include <experimental/filesystem>
#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)

#elif defined(__EMSCRIPTEN__)
#define EMSCRIPTENLIB 1
#include <unistd.h>
#include <termios.h>
#define DLLCALL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))

#endif

typedef std::string String;
typedef std::wstring WString;
#define LINE_FEED_CHAR (static_cast<char>(10))

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
{
public:
    static void Clear();
    static void WriteLine(const String &s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {});
    static void Write(const String &s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {});
    static void WriteLine(const WString &s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {});
    static void Write(const WString &s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {});
    static void WriteLine();
    static void Pause();
    static int PauseAny(bool printWhenPressed = false);

private:
    static void EnableVirtualTermimalProcessing();
    static void SetVirtualTerminalFormat(ConsoleForeground foreground, ConsoleBackground background, std::set<ConsoleTextStyle> styles);
    static void ResetTerminalFormat();
};

class Strings
{
public:
    static String WideStringToString(const WString &wstr);
    static WString StringToWideString(const String &str);
    static WString ToUpper(const WString &data);
    static String ToUpper(const String &data);
    static WString ToLower(const WString &data);
    static String ToLower(const String &data);
};

String Strings::WideStringToString(const WString &wstr)
{
    if (wstr.empty())
    {
        return String();
    }
    size_t pos;
    size_t begin = 0;
    String ret;
    size_t size;
#ifdef WINDOWSLIB
    pos = wstr.find(static_cast<wchar_t>(0), begin);
    while (pos != WString::npos && begin < wstr.length())
    {
        WString segment = WString(&wstr[begin], pos - begin);
        wcstombs_s(&size, nullptr, 0, &segment[0], _TRUNCATE);
        String converted = String(size, 0);
        wcstombs_s(&size, &converted[0], size, &segment[0], _TRUNCATE);
        ret.append(converted);
        begin = pos + 1;
        pos = wstr.find(static_cast<wchar_t>(0), begin);
    }
    if (begin <= wstr.length())
    {
        WString segment = WString(&wstr[begin], wstr.length() - begin);
        wcstombs_s(&size, nullptr, 0, &segment[0], _TRUNCATE);
        String converted = String(size, 0);
        wcstombs_s(&size, &converted[0], size, &segment[0], _TRUNCATE);
        converted.resize(size - 1);
        ret.append(converted);
    }
#elif defined LINUXLIB
    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);
    }
#elif defined MACOSLIB
#endif

    return ret;
}

WString Strings::StringToWideString(const String &str)
{
    if (str.empty())
    {
        return WString();
    }

    size_t pos;
    size_t begin = 0;
    WString ret;
    size_t size;

#ifdef WINDOWSLIB
    pos = str.find(static_cast<char>(0), begin);
    while (pos != String::npos)
    {
        String segment = String(&str[begin], pos - begin);
        WString converted = WString(segment.size() + 1, 0);

        mbstowcs_s(&size, &converted[0], converted.size(), &segment[0], _TRUNCATE);
        converted.resize(size - 1);
        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() + 1, 0);
        mbstowcs_s(&size, &converted[0], converted.size(), &segment[0], _TRUNCATE);
        converted.resize(size - 1);
        ret.append(converted);
    }
#elif defined LINUXLIB
    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);
    }
#elif defined MACOSLIB
#endif

    return ret;
}

WString Strings::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;
}

String Strings::ToUpper(const String &data)
{
    return WideStringToString(ToUpper(StringToWideString(data)));
}

WString Strings::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;
}

String Strings::ToLower(const String &data)
{
    return WideStringToString(ToLower(StringToWideString(data)));
}

void Console::Clear()
{

#ifdef WINDOWSLIB
    std::system(u8"cls");
#elif defined LINUXLIB
    std::system(u8"clear");
#elif defined EMSCRIPTENLIB
    emscripten::val::global()["console"].call<void>(u8"clear");
#elif defined MACOSLIB
#endif
}

void Console::Pause()
{
    char c;
    do
    {
        c = getchar();
    } while (c != LINE_FEED_CHAR);
}

int Console::PauseAny(bool printWhenPressed)
{
    int ch;
#ifdef WINDOWSLIB
    ch = _getch();
#elif defined LINUXLIB
    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);
#elif defined MACOSLIB
#endif
    return ch;
}

void Console::EnableVirtualTermimalProcessing()
{
#if defined WINDOWSLIB
    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
}

void Console::ResetTerminalFormat()
{
    std::cout << u8"\033[0m";
}

void Console::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;
}

void Console::Write(const String &s, ConsoleForeground foreground, ConsoleBackground background, std::set<ConsoleTextStyle> styles)
{
    EnableVirtualTermimalProcessing();
    SetVirtualTerminalFormat(foreground, background, styles);
    String str = s;
#ifdef WINDOWSLIB
    WString unicode = Strings::StringToWideString(str);
    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), static_cast<DWORD>(unicode.length()), nullptr, nullptr);
#elif defined LINUXLIB
    std::cout << str;
#elif defined MACOSLIB
#endif
    ResetTerminalFormat();
}

void Console::WriteLine(const String &s, ConsoleForeground foreground, ConsoleBackground background, std::set<ConsoleTextStyle> styles)
{
    Write(s, foreground, background, styles);
    std::cout << std::endl;
}

void Console::Write(const WString &s, ConsoleForeground foreground, ConsoleBackground background, std::set<ConsoleTextStyle> styles)
{
    EnableVirtualTermimalProcessing();
    SetVirtualTerminalFormat(foreground, background, styles);
    WString str = s;

#ifdef WINDOWSLIB
    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), str.c_str(), static_cast<DWORD>(str.length()), nullptr, nullptr);
#elif defined LINUXLIB
    std::cout << Strings::WideStringToString(str); //NEED TO BE FIXED. ADD locale parameter
#elif defined MACOSLIB
#endif
    ResetTerminalFormat();
}

void Console::WriteLine(const WString &s, ConsoleForeground foreground, ConsoleBackground background, std::set<ConsoleTextStyle> styles)
{
    Write(s, foreground, background, styles);
    std::cout << std::endl;
}

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::PauseAny();
    return 0;
}

答案 22 :(得分:0)

如果只想大写,请尝试使用此功能。

#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

答案 23 :(得分:0)

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

答案 24 :(得分:-1)

如果您只关心8位字符(除了MilanBabuš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

答案 25 :(得分:-1)

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

答案 26 :(得分:-1)

不使用任何库:

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

答案 27 :(得分:-1)

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

这样做

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循环。

记住字符串大小也会返回分隔符,所以请使用&lt;而不是&lt; =在你的循环测试中。

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

答案 28 :(得分:-1)

您可以在C ++ 17中简单地使用它

for(auto i : str) putchar(toupper(i));

答案 29 :(得分:-1)

std::string str = "STriNg oF mIxID CasE lETteRS"

C ++ 11

  • 使用for_each

    std::for_each(str.begin(), str.end(), [](char & 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)

答案 30 :(得分:-2)

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

答案 31 :(得分:-3)

我使用这个解决方案。我知道你不应该修改那个数据区....但我认为这主要是因为缓冲区溢出错误和空字符....上层的东西是不一样的。

void to_upper(const std::string str) {
    std::string::iterator it;
    int i;
    for ( i=0;i<str.size();++i ) {
        ((char *)(void *)str.data())[i]=toupper(((char *)str.data())[i]);
    }
}