Convertir una cadena en C ++ a mayúscula

¿Cómo podría uno convertir una cadena en mayúscula? Los ejemplos que he encontrado en Google solo tienen que ver con los caracteres.

Algoritmos de cadena de refuerzo:

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

Solución corta usando C ++ 11 y 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: Un par de problemas con la solución superior:

21.5 Utilidades de secuencia terminadas en nulo

El contenido de estos encabezados debe ser el mismo que el de los encabezados de la Biblioteca C estándar , , , y […]

  • Lo que significa que los miembros de cctype pueden ser macros no adecuados para el consumo directo en algoritmos estándar.

  • Otro problema con el mismo ejemplo es que no emite el argumento o verifica que esto no sea negativo; esto es especialmente peligroso para los sistemas en los que se firma el char leña. (El motivo es: si esto se implementa como una macro, probablemente use una tabla de búsqueda y los índices de su argumento en esa tabla. Un índice negativo le dará UB).

¿Tienes caracteres ASCII o internacionales en cadenas?

Si es el último caso, “uppercasing” no es tan simple, y depende del alfabeto utilizado. Hay alfabetos unicameral y bicameral. Solo los alfabetos bicamerales tienen caracteres diferentes para mayúsculas y minúsculas. Además, hay caracteres compuestos, como la letra mayúscula latina ‘DZ’ (\ u01F1 ‘DZ’) que utilizan el llamado caso del título . Esto significa que solo se cambia el primer carácter (D).

Sugiero que busque en la UCI , y la diferencia entre las asignaciones de casos simples y completos. Esto podría ayudar:

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

O,

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

Este problema se puede vectorizar con SIMD para el juego de caracteres ASCII.


Comparaciones de aceleración:

Pruebas preliminares con x86-64 gcc 5.2 -O3 -march=native en Core2Duo (Merom). La misma cadena de 120 caracteres (ASCII mezclados en minúscula y no minúscula), convertida en un bucle 40M veces (sin encriptación cruzada de archivos, por lo que el comstackdor no puede optimizar ni sacar ninguno del bucle). Los mismos búfers de origen y destino, por lo que no hay malloc ni efectos de memoria / caché: los datos están calientes en la memoria caché L1 todo el tiempo, y estamos puramente vinculados a la CPU.

  • boost::to_upper_copy() : 198.0s . Sí, Boost 1.58 en Ubuntu 15.10 es realmente tan lento. Inicialicé y puse en un solo paso el asm en un depurador, y es realmente, muy malo: ¡hay un dynamic_cast de una variable de localización por personaje! (dynamic_cast toma múltiples llamadas a strcmp). Esto sucede con LANG=C y con LANG=en_CA.UTF-8 .

    No probé usando un RangeT distinto de std :: string. Tal vez la otra forma de to_upper_copy optimice mejor, pero creo que siempre tendrá espacio new / malloc para la copia, por lo que es más difícil de probar. Tal vez algo que hice difiere de un caso de uso normal, y tal vez normalmente se detuvo. G ++ puede levantar las cosas de la configuración regional fuera del bucle por personaje. Mi lectura de bucle de std::string y escribir en un char dstbuf[4096] tiene sentido para las pruebas.

  • loop llamando a glibc toupper : 6.67s (sin embargo, no verificando el resultado int para UTF-8 multi-byte potencial. Esto es importante para el turco).

  • Bucle ASCII-only: 8.79s (mi versión de referencia para los resultados a continuación). Al parecer, una búsqueda de tabla es más rápida que una cmov , con la tabla caliente en L1 de todos modos.
  • Solo vectorizado solo ASCII: 2.51s . (120 caracteres está a medio camino entre el peor caso y el mejor de los casos, ver más abajo)
  • Vectorizado manualmente solo ASCII: 1.35s

Consulte también esta pregunta acerca de cómo toupper() es lento en Windows cuando se establece una configuración regional .


Me sorprendió que Boost sea un orden de magnitud más lento que las otras opciones. Comprobé dos veces que tenía habilitado -O3 , e incluso hice un solo paso en el asm para ver qué estaba haciendo. Es casi exactamente la misma velocidad con clang ++ 3.8. Tiene grandes gastos generales dentro del bucle por personaje. El resultado de perf record / report perforación (para el evento de perf de cycles ) es:

  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% ... 

Autovectorización

Gcc y clang solo auto-vectorizarán bucles cuando se conoce el recuento de iteraciones antes del bucle. (es decir, los bucles de búsqueda como la implementación plain-C de strlen no se autovectorizarán).

Por lo tanto, para cadenas lo suficientemente pequeñas como para caber en la memoria caché, obtenemos una aceleración significativa para cadenas de ~ 128 caracteres de largo antes de hacer strlen primero. Esto no será necesario para cadenas de longitud explícita (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 

Cualquier libc decente tendrá un strlen eficiente que es mucho más rápido que el bucle de un byte a la vez, por lo que los loops de strlen y toupper vectorizados por separado son más rápidos.

Línea de base: un bucle que verifica la terminación de un 0 sobre la marcha.

Tiempos para iteraciones de 40M, en Core2 (Merom) 2.4GHz. gcc 5.2 -O3 -march=native . (Ubuntu 15.10). dst != src (entonces hacemos una copia), pero no se superponen (y no están cerca). Ambos están alineados.

  • 15 cadena de caracteres: línea base: 1.08s. autovec: 1.34s
  • 16 cadena de caracteres: línea de base: 1.16s. autovec: 1.52s
  • 127 cadena de caracteres: línea de base: 8.91s. autovec: 2.98s // limpieza no vectorial tiene 15 caracteres para procesar
  • 128 cadena de caracteres: línea base: 9.00s. autovec: 2.06s
  • 129 cadena de caracteres: línea base: 9.04s. autovec: 2.07s // limpieza no vectorial tiene 1 char para procesar

Algunos resultados son un poco diferentes con clang.

El bucle de microbenchmark que llama a la función está en un archivo separado. De lo contrario, entra en línea y strlen() sale del bucle, y se ejecuta dramáticamente más rápido, especialmente. para 16 cadenas de caracteres (0.187s).

Esto tiene la gran ventaja de que gcc puede auto-vectorizarlo para cualquier architecture, pero la mayor desventaja es que es más lento para el caso generalmente común de cadenas pequeñas.


Entonces, hay grandes aceleraciones, pero la auto-vectorización del comstackdor no es un gran código, especialmente. para la limpieza de los últimos hasta 15 caracteres.

Vectorización manual con intrínseca SSE:

Basado en mi función case-flip que invierte el caso de cada carácter alfabético. Aprovecha el "truco de comparación sin signo", donde puede hacer low < a && a <= high con una sola comparación sin signo por desplazamiento de rango, de modo que cualquier valor menor que low ajusta a un valor que es mayor que high . (Esto funciona si low y high no están muy separados).

SSE solo tiene una comparación firmada-mayor, pero aún podemos usar el truco de "comparación sin signo" al desplazar el rango hasta el final del rango firmado: restar 'a' + 128, por lo que los caracteres alfabéticos van desde -128 a -128 +25 (-128 + 'z' - 'a')

Tenga en cuenta que agregar 128 y restar 128 es lo mismo para enteros de 8 bits. No hay ningún lugar para llevar el equipaje de mano, por lo que es solo xor (sin llevar), volteando el bit 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 esta función que funciona para un vector, podemos llamarlo en un bucle para procesar una cadena completa. Como ya estamos apuntando a SSE2, podemos hacer una verificación vectorizada al final de la cadena al mismo tiempo.

También podemos hacer mucho mejor para la "limpieza" de los últimos hasta 15 bytes que quedan después de hacer vectores de 16B: la mayúscula es idempotente, por lo que volver a procesar algunos bytes de entrada está bien. Hacemos una carga desalineada de los últimos 16B de la fuente y la almacenamos en el búfer de destino solapando la última tienda de 16B del bucle.

El único momento en que esto no funciona es cuando toda la cadena está por debajo de 16B: incluso cuando dst=src , lectura-modificación-escritura no atómica no es lo mismo que no tocar algunos bytes, y puede romper el código multiproceso.

Tenemos un bucle escalar para eso, y también para alinear src . Como no sabemos dónde estará el 0 de terminación, una carga desalineada de src podría cruzar a la página siguiente y segfault. Si necesitamos bytes en un bloque alineado de 16B, siempre es seguro cargar todo el segmento 16B alineado.

Fuente completa: en un 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; } 

Tiempos para iteraciones de 40M, en Core2 (Merom) 2.4GHz. gcc 5.2 -O3 -march=native . (Ubuntu 15.10). dst != src (entonces hacemos una copia), pero no se superponen (y no están cerca). Ambos están alineados.

  • 15 cadena de caracteres: línea base: 1.08s. autovec: 1.34s. manual: 1.29s
  • 16 cadena de caracteres: línea de base: 1.16s. autovec: 1.52s. manual: 0.335s
  • 31 cadena de caracteres: manual: 0.479s
  • 127 cadena de caracteres: línea de base: 8.91s. autovec: 2.98s. manual: 0.925s
  • 128 cadena de caracteres: línea base: 9.00s. autovec: 2.06s. manual: 0.931s
  • 129 cadena de caracteres: línea base: 9.04s. autovec: 2.07s. manual: 1.02s

(En realidad sincronizado con _mm_store en el bucle, no _mm_storeu , porque storeu es más lento en Merom incluso cuando la dirección está alineada. Está bien en Nehalem y más tarde. También dejé el código como está por ahora, en lugar de corregir el error para copiar la terminación 0 en algunos casos, porque no quiero volver a cronometrar todo).

Entonces, para cadenas cortas de más de 16B, esto es mucho más rápido que el auto-vectorizado. Las longitudes de un ancho de menos de un vector no presentan un problema. Pueden ser un problema cuando operan en el lugar, debido a un puesto de desvío de tiendas. (Pero tenga en cuenta que todavía está bien procesar nuestra propia salida, en lugar de la entrada original, porque toupper es idempotente).

Hay muchas posibilidades de ajustar esto para diferentes casos de uso, dependiendo de lo que desee el código circundante, y de la microarchitecture objective. Hacer que el comstackdor emita un buen código para la parte de limpieza es complicado. Usar ffs(3) (que comstack a bsf o tzcnt en x86) parece ser bueno, pero obviamente ese bit necesita un replanteamiento ya que noté un error después de escribir la mayor parte de esta respuesta (ver los comentarios de FIXME).

Se pueden obtener reducciones de velocidad de vector para cadenas aún más pequeñas con cargas / tiendas movq o movd . Personalice según sea necesario para su caso de uso.


UTF-8:

Podemos detectar cuándo nuestro vector tiene bytes con el bit alto establecido, y en ese caso recurrir a un bucle escalar de utf-8-aware para ese vector. El punto dst puede avanzar en una cantidad diferente que el puntero src , pero una vez que regresemos a un puntero src alineado, seguiremos haciendo tiendas vectoriales no alineadas a dst .

Para el texto que es UTF-8, pero consiste principalmente en el subconjunto ASCII de UTF-8, esto puede ser bueno: alto rendimiento en el caso común con un comportamiento correcto en todos los casos. Sin embargo, cuando hay una gran cantidad de elementos que no son ASCII, probablemente será peor que permanecer en el circuito escalar UTF-8 todo el tiempo.

Hacer que el inglés sea más rápido a expensas de otros idiomas no es una decisión a prueba de futuro si la desventaja es significativa.


Locale-aware:

En la configuración regional turca ( tr_TR ), el resultado correcto de toupper('i') es 'İ' (U0130), no 'I' (ASCII simple). Vea los comentarios de Martin Bonner sobre una pregunta acerca de que tolower() es lento en Windows.

También podemos verificar la existencia de una lista de excepciones y un repliegue escalar, como para los caracteres de entrada UTF8 de múltiples bytes.

Con esta gran complejidad, SSE4.2 PCMPISTRM o algo así podría hacer muchas de nuestras comprobaciones de una vez.

El más rápido si solo usa caracteres ASCII :

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

Tenga en cuenta que este código se ejecuta más rápido, pero solo funciona en ASCII y no es una solución “abstracta”.

Si necesita soluciones UNICODE o soluciones más convencionales y abstractas, busque otras respuestas y trabaje con métodos de cadenas de C ++.

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

El siguiente funciona para mi.

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

Esto funcionará mejor que todas las respuestas que usan la función global toupper, y es presumiblemente lo que boost :: to_upper está haciendo debajo.

Esto se debe a que :: toupper debe buscar la configuración regional, ya que podría haber sido modificada por un hilo diferente, para cada invocación, mientras que aquí solo la llamada a locale () tiene esta penalización. Y buscar el lugar generalmente implica tomar un candado.

Esto también funciona con C ++ 98 después de reemplazar el auto, usar el nuevo str.data no const (), y agregar un espacio para romper el cierre de la plantilla (“>>” a “>>”) de esta manera:

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

prueba la función toupper() ( #include ). acepta caracteres como argumentos, las cadenas están formadas por caracteres, por lo que tendrá que iterar sobre cada carácter individual que, cuando se junta, forman la cadena

Aquí está el último código con C ++ 11

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

no estoy seguro de que haya una función incorporada. Prueba esto:

Incluya las bibliotecas ctype.h O cctype, así como stdlib.h como parte de las directivas de preprocesador.

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

Mi solución (borrar 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++; } } 

Sin usar ninguna 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; } 

Si solo le interesan los caracteres de 8 bits (que todas las otras respuestas, excepto Milan Babuškov, suponen también), puede obtener la velocidad más rápida generando una tabla de búsqueda en tiempo de comstackción mediante metaprogtwigción. En ideone.com, esto funciona 7 veces más rápido que la función de biblioteca y 3 veces más rápido que una versión escrita a mano ( http://ideone.com/sb1Rup ). También se puede personalizar a través de rasgos sin ralentización.

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

con el 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.

Hacer esto

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