Converter uma seqüência de caracteres em C ++ para maiúsculas

Como se poderia converter uma string em maiúscula? Os exemplos que encontrei no googling só tem que lidar com chars.

Impulsione algoritmos de string:

#include  #include  std::string str = "Hello World"; boost::to_upper(str); std::string newstr = boost::to_upper_copy("Hello World"); 
 #include  #include  std::string str = "Hello World"; std::transform(str.begin(), str.end(),str.begin(), ::toupper); 

Solução curta usando C ++ 11 e toupper ().

 for (auto & c: str) c = toupper(c); 
 struct convert { void operator()(char& c) { c = toupper((unsigned char)c); } }; // ... string uc_str; for_each(uc_str.begin(), uc_str.end(), convert()); 

Nota: Alguns problemas com a solução principal:

21.5 Utilitários de sequência terminados em nulo

O conteúdo desses headers deve ser o mesmo dos headers da Biblioteca C padrão , , , e […]

  • O que significa que os membros do cctype podem ser macros não adequados para consumo direto em algoritmos padrão.

  • Outro problema com o mesmo exemplo é que ele não lança o argumento ou verifica se isso é não-negativo; isso é especialmente perigoso para sistemas em que o char simples é assinado. (O motivo é: se isso for implementado como uma macro, provavelmente usará uma tabela de consulta e seus índices de argumento nessa tabela. Um índice negativo fornecerá UB.)

Você tem caracteres ASCII ou internacionais em strings?

Se for o último caso, “uppercasing” não é tão simples, e depende do alfabeto usado. Existem alfabetos bicameral e unicameral. Somente alfabetos bicameral possuem caracteres diferentes para maiúsculas e minúsculas. Além disso, existem caracteres compostos, como a letra maiúscula latina ‘DZ’ (\ u01F1 ‘DZ’), que usa o chamado caso de título . Isso significa que apenas o primeiro caractere (D) é alterado.

Eu sugiro que você olhe para o ICU e a diferença entre Mapeamentos de Caso Simples e Completo. Isso pode ajudar:

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

 string StringToUpper(string strToConvert) { for (std::string::iterator p = strToConvert.begin(); strToConvert.end() != p; ++p) *p = toupper(*p); return p; } 

Ou,

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

Esse problema é vetorizável com SIMD para o conjunto de caracteres ASCII.


Comparações de aceleração:

Testes preliminares com x86-64 gcc 5.2 -O3 -march=native em um Core2Duo (Merom). A mesma cadeia de 120 caracteres (ASCII com letras minúsculas e não minúsculas mistas), convertida em um loop 40M vezes (sem inline de arquivo cruzado, portanto, o compilador não pode otimizar ou extrair nada fora do loop). Mesma fonte e buffers de destino, portanto nenhuma sobrecarga de malloc ou efeitos de memory / cache: os dados ficam quentes no cache L1 o tempo todo e estamos puramente ligados à CPU.

  • boost::to_upper_copy() : 198.0s . Sim, o Boost 1.58 no Ubuntu 15.10 é realmente tão lento. Eu criei um perfil e dei um passo no asm em um depurador, e é muito, muito ruim: há um dynamic_cast de uma variável de localidade acontecendo por personagem !!! (dynamic_cast leva várias chamadas para strcmp). Isso acontece com LANG=C e com LANG=en_CA.UTF-8 .

    Eu não testei usando um RangeT diferente de std :: string. Talvez a outra forma de to_upper_copy otimize melhor, mas acho que sempre haverá espaço new / malloc para a cópia, por isso é mais difícil de testar. Talvez algo que eu fiz seja diferente de um caso de uso normal, e talvez o g + normalmente parado possa içar o material de configuração do local do loop por caractere. Meu loop lendo de um std::string e escrevendo para um char dstbuf[4096] faz sentido para testes.

  • loop chamando glibc toupper : 6.67s (não verificando o resultado int para potencial multi-byte UTF-8, no entanto. Isso é importante para o turco.)

  • Loop somente ASCII: 8.79s (minha versão de linha de base para os resultados abaixo). Aparentemente, uma procura de tabela é mais rápida que um cmov , com a tabela quente em L1 de qualquer maneira.
  • Auto-vetorizado somente em ASCII: 2.51s . (120 chars está na metade do caminho entre o pior caso e o melhor caso, veja abaixo)
  • ASCII somente vetorizado manualmente: 1.35s

Veja também esta pergunta sobre o toupper() sendo lento no Windows quando uma localidade é configurada .


Fiquei chocado que o Boost é uma ordem de magnitude mais lenta que as outras opções. Verifiquei -O3 se eu tinha ativado o -O3 e, mesmo assim, passei um passo no asm para ver o que ele estava fazendo. É quase exatamente a mesma velocidade com o clang ++ 3.8. Tem sobrecarga enorme dentro do loop por caractere. O resultado do perf record / report do perf (para o evento 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% ... 

Autovetorização

O Gcc e o clang irão somente vetorizar loops quando a contagem de iterações for conhecida antes do loop. (isto é, loops de busca como implementação simples de strlen não serão auto-re.)

Assim, para strings pequenas o suficiente para caber no cache, obtemos uma aceleração significativa para strings ~ 128 caracteres de duração fazendo strlen primeiro. Isso não será necessário para seqüências de comprimento explícito (como 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 

Qualquer libc decente terá um strlen eficiente que é muito mais rápido do que dar um loop de byte de cada vez, portanto os loops strlen e toupper vetorizados separados são mais rápidos.

Linha de base: um loop que verifica a terminação 0 na hora.

Vezes para iterações de 40M, em um Core2 (Merom) 2.4GHz. gcc 5.2 -O3 -march=native . (Ubuntu 15.10). dst != src (então fazemos uma cópia), mas eles não se sobrepõem (e não estão próximos). Ambos estão alinhados.

  • 15 cadeia de caractere: linha de base: 1.08s. autovec: 1.34s
  • 16 string de caracteres: linha de base: 1,16s. autovec: 1.52s
  • 127 cadeia de caracteres: linha de base: 8,91s. autovec: 2.98s // limpeza não vetorial tem 15 caracteres para processar
  • 128 cadeia de caracteres: linha de base: 9,00s. autovec: 2.06s
  • 129 cadeia de caracteres: linha de base: 9.04s. autovec: 2.07s // limpeza não vetorial tem 1 caractere para processar

Alguns resultados são um pouco diferentes com o clang.

O loop de microbenchmark que chama a function está em um arquivo separado. Caso contrário, o inline e o strlen() serão retirados do loop e serão executados de maneira muito mais rápida, esp. para 16 caracteres (0,187s).

Isto tem a grande vantagem de que o gcc pode auto-vetorizar-lo para qualquer arquitetura, mas a maior desvantagem é que é mais lento para o caso comum das pequenas cadeias de caracteres.


Portanto, há grandes acelerações, mas a autovetorização do compilador não cria um código excelente, esp. para limpeza dos últimos até 15 caracteres.

Vetorização manual com intrínsecos SSE:

Com base na minha function case-flip, que inverte o caso de cada caractere alfabético. Ele tira proveito do "truque de comparação não assinado", em que você pode fazer low < a && a <= high com uma única comparação sem sinal por variação de intervalo, de modo que qualquer valor menor que low superior a um valor maior que high . (Isso funciona se low e high não estiverem muito distantes).

O SSE tem apenas uma comparação assinada maior, mas ainda podemos usar o truque "comparar não assinado" ao alternar o intervalo para a parte inferior do intervalo sinalizado: Subtraia 'a' + 128, para que os caracteres alfabéticos variem de -128 a -128 +25 (-128 + 'z' - 'a')

Note que adicionar 128 e subtrair 128 é a mesma coisa para inteiros de 8 bits. Não há lugar para o carry ir, então é apenas xor (add carryless), lançando o bit mais alto.

 #include  __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 } 

Dada essa function que funciona para um vetor, podemos chamá-lo em um loop para processar uma string inteira. Como já estamos segmentando o SSE2, podemos fazer uma verificação vetorizada de fim de string ao mesmo tempo.

Também podemos fazer muito melhor para a "limpeza" dos últimos bytes de até 15 bytes que restam depois de fazer vetores de 16B: o revestimento superior é idempotente, então o reprocessamento de alguns bytes de input é bom. Fazemos uma carga não alinhada dos últimos 16B da fonte e armazenamos no buffer dest sobreposto ao último 16B store do loop.

A única vez que isso não funciona é quando a string inteira está abaixo de 16B: Mesmo quando dst=src , leitura não-atômica-escrita não-atômica não é a mesma coisa que não tocar em alguns bytes, e pode quebrar o código multithread.

Nós temos um loop escalar para isso, e também para alinhar src . Como não sabemos onde o 0 será terminado, um carregamento não alinhado do src pode passar para a próxima página e segfault. Se precisarmos de quaisquer bytes em um bloco de 16B alinhado, é sempre seguro carregar todo o bloco 16B alinhado.

Fonte completa: em um githubista .

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

Vezes para iterações de 40M, em um Core2 (Merom) 2.4GHz. gcc 5.2 -O3 -march=native . (Ubuntu 15.10). dst != src (então fazemos uma cópia), mas eles não se sobrepõem (e não estão próximos). Ambos estão alinhados.

  • 15 cadeia de caractere: linha de base: 1.08s. autovec: 1.34s. manual: 1.29s
  • 16 string de caracteres: linha de base: 1,16s. autovec: 1.52s. manual: 0,333s
  • 31 cadeia de caracteres: manual: 0,479s
  • 127 cadeia de caracteres: linha de base: 8,91s. autovec: 2.98s. manual: 0.925s
  • 128 cadeia de caracteres: linha de base: 9,00s. autovec: 2.06s. manual: 0.931s
  • 129 cadeia de caracteres: linha de base: 9.04s. autovec: 2.07s. manual: 1.02s

(Na verdade, com _mm_store no loop, não _mm_storeu , porque storeu é mais lento no Merom mesmo quando o endereço está alinhado. Está bom no Nehalem e mais tarde. Também deixei o código como está por enquanto, em vez de corrigir a falha para copiar o 0 final em alguns casos, porque eu não quero voltar a tempo tudo.)

Portanto, para strings curtas com mais de 16B, isso é muito mais rápido que o autovetorializado. Comprimentos um-menos-que-um-largura-vector não apresentam um problema. Eles podem ser um problema ao operar no local, devido a uma parada de encaminhamento de loja. (Mas note que ainda é bom processar nossa própria saída, em vez da input original, porque o toupper é idempotente).

Há muito espaço para ajustar isso para diferentes casos de uso, dependendo do que o código circundante quer e da microarquitetura de destino. Conseguir o compilador para emitir um código legal para a parte de limpeza é complicado. Usar ffs(3) (que compila para bsf ou tzcnt em x86) parece ser bom, mas obviamente esse bit precisa repensar uma vez que notei um bug depois de escrever a maior parte desta resposta (veja os comentários do FIXME).

Velocidades vetoriais para seqüências de caracteres ainda menores podem ser obtidas com cargas / armazenamentos movq ou movd . Personalize conforme necessário para o seu caso de uso.


UTF-8:

Nós podemos detectar quando nosso vetor tem algum byte com o bit alto ajustado, e nesse caso voltar para um loop escalar utf-8-aware para aquele vetor. O ponto dst pode avançar por um valor diferente do ponteiro src , mas quando voltarmos para um ponteiro src alinhado, ainda faremos apenas armazenamentos vetoriais desalinhados em dst .

Para o texto que é UTF-8, mas consiste principalmente no subconjunto ASCII de UTF-8, isso pode ser bom: alto desempenho no caso comum com o comportamento correto em todos os casos. Quando há muitos não-ASCII, provavelmente será pior do que permanecer no laço escalar consciente UTF-8 o tempo todo.

Tornar o inglês mais rápido às custas de outras línguas não é uma decisão à prova do futuro se a desvantagem for significativa.


Com reconhecimento de local:

Na localidade turca ( tr_TR ), o resultado correto do toupper('i') é 'İ' (U0130), não 'I' (ASCII simples). Veja os comentários de Martin Bonner sobre uma questão sobre tolower() ser lenta no Windows.

Também podemos verificar uma lista de exceções e um fallback para escalar, como para caracteres de input UTF8 de vários bytes.

Com tanta complexidade, o SSE4.2 PCMPISTRM ou algo assim pode ser capaz de fazer muitas das nossas verificações de uma só vez.

O mais rápido se você usar apenas caracteres ASCII :

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

Por favor, note que este código corre mais rápido, mas só funciona em ASCII e não é uma solução “abstrata”.

Se você precisar de soluções UNICODE ou soluções mais convencionais e abstratas, procure outras respostas e trabalhe com methods de strings C ++.

Use um lambda.

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

O seguinte funciona para mim.

 #include  void toUpperCase(std::string& str) { std::transform(str.begin(), str.end(), str.begin(), ::toupper); } int main() { std::string str = "hello"; toUpperCase(&str); } 
 //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; } 
 inline void strtoupper(char* str) { while (*str) { *str = toupper((unsigned char)*str); str++; } } 
 #include  #include  std::string str = "Hello World!"; auto & f = std::use_facet>(std::locale()); f.toupper(str.data(), str.data() + str.size()); 

Isso funcionará melhor do que todas as respostas que usam a function global toupper, e é presumivelmente o que boost :: to_upper está fazendo por baixo.

Isso ocorre porque :: o toupper precisa procurar o código do idioma – porque ele pode ter sido alterado por um thread diferente – para cada chamada, enquanto aqui apenas a chamada para o locale () tem essa penalidade. E olhando para o local geralmente envolve tomar um bloqueio.

Isso também funciona com o C ++ 98 depois de replace o automático, o uso do novo não-constante str.data () e adicionar um espaço para quebrar o fechamento do modelo (“>>” para “>>”) assim:

 std::use_facet > & f = std::use_facet >(std::locale()); f.toupper(const_cast(str.data()), str.data() + str.size()); 
 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 ); 
 std::string value; for (std::string::iterator p = value.begin(); value.end() != p; ++p) *p = toupper(*p); 

tente a function toupper() ( #include ). ele aceita caracteres como argumentos, strings são compostas de caracteres, então você terá que iterar sobre cada caractere individual que, quando juntos, compõem a string

Aqui está o código mais recente com o C ++ 11

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

Não tenho certeza se existe uma function incorporada. Tente isto:

Inclua as bibliotecas ctype.h ou cctype, bem como o stdlib.h como parte das diretivas do pré-processador.

 string StringToUpper(string strToConvert) {//change each element of the string to upper case for(unsigned int i=0;i 

Minha solução (limpando 6º bit para alfa):

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

Sem usar nenhuma biblioteca:

 std::string YourClass::Uppercase(const std::string & Text) { std::string UppperCaseString; UppperCaseString.reserve(Text.size()); for (std::string::const_iterator it=Text.begin(); it(0x20)) : *it); } return UppperCaseString; } 

Se você está preocupado apenas com caracteres de 8 bits (que todas as outras respostas, exceto Milan Babuškov também), você pode obter a velocidade mais rápida gerando uma tabela de consulta em tempo de compilation usando metaprogramação. No ideone.com isso é executado 7x mais rápido que a function de biblioteca e 3x mais rápido que uma versão escrita à mão ( http://ideone.com/sb1Rup ). Também é personalizável através de características sem abrandar.

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

com caso de uso:

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

For an in depth (many page) decription of how it works allow me to shamelessly plug my blog: http://metaporky.blogspot.de/2014/07/part-4-generating-look-up-tables-at.html

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

This c++ function always returns the upper case string…

 #include  #include  using namespace std; string toUpper (string str){ locale loc; string n; for (string::size_type i=0; i 

ALL of these solutions on this page are harder than they need to be.

Faça isso

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

RegName is your string . Get your string size don't use string.size() as your actual tester, very messy and can cause issues. then. the most basic for loop.

remember string size returns the delimiter too so use < and not <= in your loop test.

output will be: some string that you want converted

I use this solution. I know you’re not supposed to modify that data area…. but I think that’s mostly for buffer overrun bugs and null character…. upper casing things isn’t the same.

 void to_upper(const std::string str) { std::string::iterator it; int i; for ( i=0;i 

In all the machines I tested, it was faster. Perhaps because he is not concerned with a very wide range of characters. Or because using switch() it makes a jump table, do not know how it works in the assembly … just know that is faster 😛

 string Utils::String::UpperCase(string CaseString) { for (unsigned short i = 0, tamanho = CaseString.length(); i < tamanho; i++) { switch (CaseString[i]) { case 'a': CaseString[i] = 'A'; break; case 'b': CaseString[i] = 'B'; break; case 'c': CaseString[i] = 'C'; break; case 'd': CaseString[i] = 'D'; break; case 'e': CaseString[i] = 'E'; break; case 'f': CaseString[i] = 'F'; break; case 'g': CaseString[i] = 'G'; break; case 'h': CaseString[i] = 'H'; break; case 'i': CaseString[i] = 'I'; break; case 'j': CaseString[i] = 'J'; break; case 'k': CaseString[i] = 'K'; break; case 'l': CaseString[i] = 'L'; break; case 'm': CaseString[i] = 'M'; break; case 'n': CaseString[i] = 'N'; break; case 'o': CaseString[i] = 'O'; break; case 'p': CaseString[i] = 'P'; break; case 'q': CaseString[i] = 'Q'; break; case 'r': CaseString[i] = 'R'; break; case 's': CaseString[i] = 'S'; break; case 't': CaseString[i] = 'T'; break; case 'u': CaseString[i] = 'U'; break; case 'v': CaseString[i] = 'V'; break; case 'w': CaseString[i] = 'W'; break; case 'x': CaseString[i] = 'X'; break; case 'y': CaseString[i] = 'Y'; break; case 'z': CaseString[i] = 'Z'; break; } } return CaseString; }