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

如何将字符串转换为大写。我从谷歌上找到的例子只涉及字符。

683364 次浏览

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

#include <algorithm>
#include <string>


std::string str = "Hello World";
std::transform(str.begin(), str.end(),str.begin(), ::toupper);
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库头文件<ctype.h>, <wctype.h>, <string.h>, <wchar.h>和<stdlib.h>相同。[…]

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

  • 同一个例子的另一个问题是,它不强制转换实参,也不验证这是非负的;这对于符号为普通char的系统尤其危险。(原因是:如果这是作为一个宏实现的,它可能会使用一个查找表和你的参数索引到那个表。负指数会给你UB。)

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

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

升压字符串算法:

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

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

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

我建议你看看加护病房,以及简单和全大小写映射之间的区别。这可能会有帮助:

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

//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;
}
std::string value;
for (std::string::iterator p = value.begin(); value.end() != p; ++p)
*p = toupper(*p);
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;
}

只要你能接受ascii,并且你可以提供一个指向RW内存的有效指针,在C语言中有一个简单而有效的一行代码:

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

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

本页上的所有这些解决方案都比它们需要的要难。

这样做

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

记住,字符串大小也返回分隔符,所以使用<而不是<=在循环测试中。

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

我用这个解。我知道你不应该修改数据区域....但我认为这主要是缓冲区溢出错误和空字符....大写字母就不一样了。

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

较快的如果你只使用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++ 11和toupper()的简单解决方案。

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

不使用任何库:

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

这是c++ 11的最新代码

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

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

如果您只关心8位字符(除了Milan babukov以外的所有答案都假设),您可以通过在编译时使用元编程生成查找表来获得最快的速度。在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

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

下面的方法对我有用。

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


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

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


加速比较:

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

  • < p > boost::to_upper_copy<char*, std::string>(): 198.0秒。是的,Ubuntu 15.10上的Boost 1.58真的是这么慢。我在调试器中对asm进行了概要分析和单步执行,它真的很糟糕:每个字符都会发生一个区域变量的dynamic_cast !!(dynamic_cast对strcmp进行多次调用)。这发生在LANG=CLANG=en_CA.UTF-8中。

    我没有使用std::string以外的RangeT进行测试。也许是to_upper_copy的另一种形式优化得更好,但我认为它总是会为副本提供new/malloc空间,因此更难测试。也许我所做的某些事情与正常的用例不同,也许通常停止的g++可以将区域设置内容从每个字符循环中提升出来。我的循环从std::string读取并写入char dstbuf[4096]对于测试是有意义的

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

  • 仅ascii循环:8.79秒(下面结果的基线版本。)显然,表查找比cmov更快,无论如何,L1中的表是热的。
  • 仅ascii自动向量化:2.51秒。(120字符是最差情况和最佳情况之间的中间值,见下文)
  • 仅ascii手动向量化:1.35秒

另见当设置locale时,这个关于toupper()在Windows上运行缓慢的问题


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

4000万次迭代,Core2 (Merom) 2.4GHz。-O3 -march=native. gcc 5.2。(Ubuntu 15.10)。dst != src(所以我们创建了一个副本),但它们没有重叠(并且不在附近)。两者都是对齐的。

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

一些结果与clang略有不同。

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

这样做的主要优点是gcc可以对任何体系结构自动向量化,但主要缺点是对于小字符串的常见情况来说速度较慢。


因此,可以大大提高速度,但编译器自动向量化并不能生成很好的代码,特别是对于最后到15个字符的清理。

使用SSE intrinsic手工向量化:

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

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

注意,加128和减128对于8位整数是一样的。进位无处可去,所以它只是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,所以我们可以同时做一个向量化的字符串结束检查。

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

唯一不能工作的时候是整个字符串在16B以下:即使dst=src,非原子的read-modify-write是,这与根本不触及某些字节是一样的,并且会破坏多线程代码。

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

完整源代码:在github的一个要点

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

4000万次迭代,Core2 (Merom) 2.4GHz。-O3 -march=native. gcc 5.2。(Ubuntu 15.10)。dst != src(所以我们创建了一个副本),但它们没有重叠(并且不在附近)。两者都是对齐的。

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

(实际上在循环中使用_mm_store计时,而不是_mm_storeu,因为即使地址对齐,storeu在Merom上也较慢。尼哈勒姆和以后都没问题。我现在也保持代码原样,而不是修复在某些情况下复制终止0的失败,因为我不想重新计时。)

对于比16B长的短字符串,这比自动向量化要快得多。长度小于一个向量的宽度不会出现问题。他们可能是一个问题,当操作在原地,因为一个商店转发摊位。(但请注意,处理我们自己的输出,而不是原始输入,仍然是可以的,因为toupper是幂等的)。

根据周围代码的需求和目标微架构,在不同的用例中有很大的调优范围。让编译器为清理部分发出良好的代码是很棘手的。使用ffs(3)(在x86上编译为bsf或tzcnt)似乎很好,但显然这一点需要重新考虑,因为我在写完大部分答案后注意到一个错误(参见FIXME评论)。

更小的字符串的矢量加速可以通过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评论道

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

有了这么多的复杂性,SSE4.2 PCMPISTRM或一些东西可能能够一次性完成很多检查。

#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,在你替换auto后,使用新的非const 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());

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

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

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

@dirkgently回答非常鼓舞人心,但我想强调的是,由于如下所示的担忧,

与from的所有其他函数一样,如果实参的值既不能表示为unsigned char也不等于EOF,则std::toupper的行为是未定义的。为了安全地将这些函数与普通字符(或有符号字符)一起使用,参数首先应该转换为无符号字符
参考: std:: toupper
由于标准没有指定普通char是有符号的还是无符号的__abc1, 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!
std::string str = "STriNg oF mIxID CasE lETteRS"

c++ 11

  • 使用for_each < p >

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

  • < p >使用变换

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

c++(仅限windows)

_strupr_s(str, str.length());

c++(使用Boost库)

boost::to_upper_copy(str)

基于Kyle_the_hacker的 ----->回答与我的额外。

Ubuntu

< p >终端 列出所有
的地区 locale -a < / p >

安装所有区域设置
sudo apt-get install -y locales locales-all < / p >

编译main.cpp
$ g++ main.cpp < / p >

运行已编译程序
$ ./a.out < / p >

结果

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ë

Ubuntu Linux - WSL from VSCODE

Ubuntu Linux - WSL

窗户

在cmd下运行VCVARS developer tools
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" < / p >

编译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 < / p >

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

结果

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


如果你只想大写,试试这个函数。

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

错误:c++ 98模式不允许基于范围的for循环

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