¿Cómo se puede convertir una cadena a mayúsculas? Los ejemplos que he encontrado en google solo tienen que ver con caracteres.
¿Cómo se puede convertir una cadena a mayúsculas? Los ejemplos que he encontrado en google solo tienen que ver con caracteres.
Respuestas:
Impulsar algoritmos de cadena:
#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");
std::string newstr(boost::to_upper_copy<std::string>("Hello World"));
#include <algorithm>
#include <string>
std::string str = "Hello World";
std::transform(str.begin(), str.end(),str.begin(), ::toupper);
toupper()
se puede implementar como una macro. Esto puede causar un problema.
toupper
. ¿Algunas ideas?
Solución corta usando C ++ 11 y toupper ().
for (auto & c: str) c = toupper(c);
c
sería del const char
tipo (de auto
)? Si es así, no puede asignarlo (debido a una const
parte) a lo que devuelve toupper(c)
.
c
necesita ser lanzado unsigned char
para que esto sea corregido.
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 principal:
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 <ctype.h>, <wctype.h>, <string.h>, <wchar.h> y <stdlib.h> [...]
Lo que significa que los cctype
miembros pueden ser macros no aptos para el consumo directo en algoritmos estándar.
Otro problema con el mismo ejemplo es que no arroja el argumento ni verifica que esto no sea negativo; Esto es especialmente peligroso para los sistemas en los que char
se firma sin formato . (La razón es: si esto se implementa como una macro, probablemente usará una tabla de búsqueda y sus argumentos indexados en esa tabla. Un índice negativo le dará UB).
Este problema es vectorizable con SIMD para el conjunto de caracteres ASCII.
Pruebas preliminares con x86-64 gcc 5.2 -O3 -march=native
en un Core2Duo (Merom). La misma cadena de 120 caracteres (ASCII minúscula y no minúscula mixta), convertida en un bucle 40M veces (sin línea cruzada entre archivos, por lo que el compilador no puede optimizar ni sacar nada del bucle). Las mismas memorias intermedias de origen y destino, por lo que no hay sobrecarga malloc o efectos de memoria / caché: los datos están calientes en la caché L1 todo el tiempo, y estamos puramente vinculados a la CPU.
boost::to_upper_copy<char*, std::string>()
: 198.0s . Sí, Boost 1.58 en Ubuntu 15.10 es realmente tan lento. Realicé un perfil y escalé el asm en un depurador, y es muy, muy malo: ¡hay una transmisión dinámica de una variable local por carácter! (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 que no sea std :: string. Tal vez la otra forma deto_upper_copy
optimiza mejor, pero creo que lo hará siempre new
/ malloc
espacio 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 detenido g ++ puede levantar el material de configuración regional del bucle por carácter. Mi ciclo de lectura de a std::string
y escritura en a char dstbuf[4096]
tiene sentido para las pruebas.
loop call glibc toupper
: 6.67s (sin embargo, no se verifica el int
resultado de un posible UTF-8 de varios bytes. Esto es importante para el turco).
cmov
, con la tabla activa en L1 de todos modos.Consulte también esta pregunta sobre la toupper()
lentitud 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. Verifiqué dos veces que había -O3
habilitado, e incluso un solo paso para ver lo que estaba haciendo. Es casi exactamente la misma velocidad con clang ++ 3.8. Tiene una gran sobrecarga dentro del bucle por personaje. El perf record
/ report
resultado (para el cycles
evento perf) 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% ...
Gcc y clang solo vectorizarán automáticamente los bucles cuando el recuento de iteraciones se conozca antes del bucle. (es decir, los bucles de búsqueda como la implementación de C simple de strlen
no se autovectorizarán).
Por lo tanto, para las cadenas lo suficientemente pequeñas como para caber en la memoria caché, obtenemos una aceleración significativa para las cadenas de ~ 128 caracteres de largo 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<len ; ++i) {
dst[i] = ascii_toupper_char(src[i]); // gcc does the vector range check with psubusb / pcmpeqb instead of pcmpgtb
}
return len;
}
Cualquier libc decente tendrá una eficiencia strlen
mucho más rápida que el bucle de un byte a la vez, por lo que los bucles strlen y toupper vectorizados por separado son más rápidos.
Línea de base: un bucle que comprueba un 0 final sobre la marcha.
Tiempos para iteraciones de 40M, en un Core2 (Merom) 2.4GHz. gcc 5.2 -O3 -march=native
. (Ubuntu 15.10). dst != src
(así que hacemos una copia), pero no se superponen (y no están cerca). Ambos están alineados.
Algunos resultados son un poco diferentes con el sonido metálico.
El bucle de microbenchmark que llama a la función está en un archivo separado. De lo contrario, se alinea y strlen()
se saca del circuito, 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 arquitectura, 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 vectorización automática del compilador no es un gran código, especialmente. para la limpieza de los últimos hasta 15 caracteres.
Basado en mi función de cambio de mayúsculas y minúsculas que invierte las mayúsculas y minúsculas de cada carácter alfabético. Aprovecha el "truco de comparación sin signo", donde puedes hacer low < a && a <= high
una sola comparación sin signo mediante el desplazamiento de rango, de modo que cualquier valor menor que se low
ajusta a un valor mayor que high
. (Esto funciona si low
y high
no están demasiado separados).
SSE solo tiene una comparación con signo mayor, pero aún podemos usar el truco de "comparación sin signo" al cambiar el rango al final del rango firmado: Reste 'a' + 128, por lo que los caracteres alfabéticos varían de -128 a -128 +25 (-128 + 'z' - 'a')
Tenga en cuenta que sumar 128 y restar 128 son lo mismo para los enteros de 8 bits. No hay a dónde ir el transporte, por lo que es solo xor (complemento sin transporte), volteando el bit alto.
#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
}
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 de fin de cadena vectorizada al mismo tiempo.
También podemos hacerlo mucho mejor para la "limpieza" de los últimos 15 bytes restantes después de hacer los vectores de 16B: la mayúscula es idempotente, por lo que volver a procesar algunos bytes de entrada está bien. Hacemos una carga no alineada de los últimos 16B de la fuente y la almacenamos en el búfer de destino superponiendo 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
la 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 src
alinearnos. Como no sabemos dónde estará la terminación 0, una carga desalineada src
podría pasar a la página siguiente y volverse por defecto. Si necesitamos bytes en un bloque 16B alineado, siempre es seguro cargar todo el bloque 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 un Core2 (Merom) 2.4GHz. gcc 5.2 -O3 -march=native
. (Ubuntu 15.10). dst != src
(así que hacemos una copia), pero no se superponen (y no están cerca). Ambos están alineados.
(Realmente cronometrado con _mm_store
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 tal como está por ahora, en lugar de arreglar el error al copiar la terminación de 0 en algunos casos, porque no quiero volver a cronometrar todo).
Entonces, para cadenas cortas de más de 16B, esto es dramáticamente más rápido que el vectorizado automático. Las longitudes uno-menos-que-un-ancho-vector no presentan un problema. Pueden ser un problema al operar en el lugar, debido a un puesto de reenvío de la tienda. (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 para ajustar esto para diferentes casos de uso, dependiendo de lo que quiera el código circundante y la microarquitectura objetivo. Conseguir que el compilador emita un buen código para la parte de limpieza es complicado. Usar ffs(3)
(que se compila en 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).
Aceleraciones vectoriales para cadenas aún más pequeñas se pueden obtener con movq
o movd
cargas / tiendas. Personalice según sea necesario para su caso de uso.
Podemos detectar cuándo nuestro vector tiene bytes con el conjunto de bits alto, y en ese caso recurrir a un bucle escalar utf-8-aware para ese vector. El dst
punto puede avanzar en una cantidad diferente al src
puntero, pero una vez que volvamos a un src
puntero alineado , seguiremos haciendo almacenamientos de vectores no alineados dst
.
Para el texto que es UTF-8, pero que consiste principalmente en el subconjunto ASCII de UTF-8, esto puede ser bueno: alto rendimiento en el caso común con comportamiento correcto en todos los casos. Sin embargo, cuando hay una gran cantidad de no ASCII, probablemente sea peor que permanecer todo el tiempo en el circuito consciente escalar UTF-8.
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 el inconveniente es significativo.
En el entorno local turco ( tr_TR
), el resultado correcto toupper('i')
es 'İ'
(U0130), no 'I'
(ASCII simple). Vea los comentarios de Martin Bonner sobre una pregunta acerca de tolower()
ser lento en Windows.
También podemos verificar si hay una lista de excepciones y una reserva para escalar allí, como para los caracteres de entrada UTF8 de varios bytes.
Con tanta complejidad, SSE4.2 PCMPISTRM
o algo así podría hacer muchas de nuestras comprobaciones de una sola vez.
¿Tiene caracteres ASCII o internacionales en cadenas?
Si es el último caso, "mayúsculas" no es tan simple, y depende del alfabeto utilizado. Hay alfabetos bicamerales y unicamerales. 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 de título . Esto significa que solo se cambia el primer carácter (D).
Le sugiero que busque en la UCI y la diferencia entre las asignaciones de casos simples y completas. Esto podría ayudar:
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;
}
**
después de los parámetros en la primera solución?
**
es un error tipográfico al intentar usar una fuente en negrita en la sintaxis del código.
toupper
se llama con números negativos.
Lo siguiente funciona para mí.
#include <algorithm>
void toUpperCase(std::string& str)
{
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
}
int main()
{
std::string str = "hello";
toUpperCase(&str);
}
toupper
se llama con números negativos.
Usa una 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);
El más rápido si usa solo 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 C ++.
C++
, pero escribió una C
respuesta aquí. (No soy uno de los
'
?
Siempre que esté bien con ASCII solo y pueda proporcionar un puntero válido a la memoria RW, hay una línea simple y muy efectiva en C:
void strtoupper(char* str)
{
while (*str) *(str++) = toupper((unsigned char)*str);
}
Esto es especialmente bueno para cadenas simples como identificadores ASCII que desea normalizar en el mismo caso de caracteres. Luego puede usar el búfer para construir una instancia de std: string.
//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;
}
for (size_t i = 0 ...
. Tampoco hay una buena razón para que sea tan difícil de leer. Esto también copia la cadena primero y luego repite sobre ella. La respuesta de @ Luke es mejor en algunos aspectos, excepto por no aprovechar las 'a'
constantes de los personajes.
#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());
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 tiene que buscar el entorno local, porque podría haber sido cambiado por un hilo diferente, para cada invocación, mientras que aquí solo la llamada a locale () tiene esta penalización. Y buscar la configuración regional generalmente implica tomar un candado.
Esto también funciona con C ++ 98 después de reemplazar el auto, usar los nuevos str.data () no constantes y agregar un espacio para romper el cierre de la plantilla (">>" a ">>") así:
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());
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 );
reserve
y back_inserter
(haciendo que la cadena solo se copie una vez). inline std::string to_lower(const std::string &s) { std::string result; result.reserve(s.size()); std::transform(s.begin(), s.end(), std::back_inserter( result ), static_cast<int(*)(int)>(std::tolower)); return result; }
std::string value;
for (std::string::iterator p = value.begin(); value.end() != p; ++p)
*p = toupper(*p);
toupper
se llama con números negativos.
pruebe la toupper()
función ( #include <ctype.h>
). 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, comprende la cadena
toupper
se llama con números negativos. Deberías haber mencionado el elenco necesario para unsigned char
.
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); });
toupper
se llama con números negativos.
La respuesta de @dirkgently es muy inspiradora, pero quiero enfatizar eso debido a la preocupación que se muestra a continuación,
Al igual que todas las demás funciones, el comportamiento de std :: toupper no está definido si el valor del argumento no es representable como char sin signo ni es igual a EOF. Para usar estas funciones de forma segura con caracteres simples (o caracteres firmados), el argumento primero se debe convertir a char sin firmar
Referencia : std :: toupper
El uso correcto de std::toupper
debe ser:
#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;
}
Salida:
Hello world!
HELLO WORLD!
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<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
}
toupper
se llama con números negativos.
Mi solución (borrar 6 bits para alfa):
#include <ctype.h>
inline void toupper(char* str)
{
while (str[i]) {
if (islower(str[i]))
str[i] &= ~32; // Clear bit 6 as it is what differs (32) between Upper and Lowercases
i++;
}
}
toupper
se llama con números negativos.
TODAS estas soluciones en esta página son más difíciles de lo necesario.
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
es tu string
. Obtenga el tamaño de su cadena no use string.size()
como su probador real, muy desordenado y puede causar problemas. luego. El for
bucle más básico .
recuerde que el tamaño de cadena también devuelve el delimitador, así que use <y no <= en su prueba de bucle.
la salida será: alguna cadena que quieras convertir
tolower
bucles simples , y la mayoría de ellos usan nombres de variables de bucle estándar como i
, no los extraños forLoop
.
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<Text.end(); ++it)
{
UppperCaseString.push_back(((0x60 < *it) && (*it < 0x7B)) ? (*it - static_cast<char>(0x20)) : *it);
}
return UppperCaseString;
}
Si solo le interesan los caracteres de 8 bits (que todas las otras respuestas, excepto Milan Babuškov también asumen), puede obtener la velocidad más rápida generando una tabla de búsqueda en tiempo de compilación utilizando metaprogramació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 es personalizable a través de rasgos sin ralentización.
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);
}
con caso de uso:
std::transform(in.begin(),in.end(),out.begin(),tableToUpper);
Para una descripción en profundidad (muchas páginas) de cómo funciona, permítame conectar descaradamente mi blog: 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;
}
Esta función de c ++ siempre devuelve la cadena de mayúsculas ...
#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;
}
Yo uso esta solución Sé que se supone que no debes modificar esa área de datos ... pero creo que eso es principalmente por errores de desbordamiento de búfer y caracteres nulos ... las cosas de mayúsculas no son lo mismo.
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]);
}
}
I know you're not supposed to modify that data area
- ¿Qué área de datos no debes modificar?
str[i] = toupper(str[i]);
perfectamente bien (bueno, no perfectamente bien, pero corrige la mayoría de las cosas mal).
::toupper
probablemente asume ASCII.