Los rangos alfabéticos en minúsculas y mayúsculas no cruzan un %32límite de "alineación" en el sistema de codificación ASCII.
Es por eso que bit 0x20es la única diferencia entre las versiones en mayúsculas / minúsculas de la misma letra.
Si este no fuera el caso, necesitaría sumar o restar 0x20, no solo alternar, y para algunas letras se realizaría para voltear otros bits más altos. (Y no habría una sola operación que pudiera alternar, y buscar caracteres alfabéticos en primer lugar sería más difícil porque no podría | = 0x20 forzar lcase).
Trucos relacionados solo con ASCII: puede verificar si hay un carácter ASCII alfabético forzando minúsculas con c |= 0x20y luego verificando si (sin signo) c - 'a' <= ('z'-'a'). Entonces, solo 3 operaciones: OR + SUB + CMP contra una constante 25. Por supuesto, los compiladores saben cómo optimizar (c>='a' && c<='z') en asm como este para usted , por lo que a lo sumo debe hacer la c|=0x20parte usted mismo. Es bastante inconveniente hacer todo el casting necesario usted mismo, especialmente para evitar promociones enteras predeterminadas para firmar int.
unsigned char lcase = y|0x20;
if (lcase - 'a' <= (unsigned)('z'-'a')) { // lcase-'a' will wrap for characters below 'a'
// c is alphabetic ASCII
}
// else it's not
Consulte también Convertir una cadena en C ++ a mayúsculas (cadena SIMDtoupper solo para ASCII, enmascarando el operando para XOR usando esa verificación).
Y también Cómo acceder a una matriz de caracteres y cambiar las letras minúsculas a mayúsculas, y viceversa
(C con intrínsecos SIMD y mayúscula escalar x86 asm para caracteres alfabéticos ASCII, dejando otros sin modificar).
La mayoría de estos trucos solo son útiles si se optimiza manualmente el procesamiento de texto con SIMD (por ejemplo, SSE2 o NEON), después de comprobar que ninguno de los chars en un vector tiene su bit alto establecido. (Y, por lo tanto, ninguno de los bytes forma parte de una codificación UTF-8 de varios bytes para un solo carácter, que podría tener diferentes inversas en mayúsculas / minúsculas). Si encuentra alguno, puede recurrir al escalar para este fragmento de 16 bytes, o para el resto de la cadena.
Incluso hay algunas configuraciones regionales donde toupper()o tolower()en algunos caracteres en el rango ASCII producen caracteres fuera de ese rango, especialmente en turco donde I ↔ ı e İ ↔ i. En esos entornos locales, necesitaría una verificación más sofisticada, o probablemente no intente utilizar esta optimización en absoluto.
Pero en algunos casos, se le permite asumir ASCII en lugar de UTF-8, por ejemplo, utilidades Unix con LANG=C(la ubicación POSIX), no en_CA.UTF-8o lo que sea.
Pero si puede verificar que es seguro, puede hacer touppercadenas de longitud media mucho más rápido que llamar toupper()en un bucle (como 5x), y la última vez que probé con Boost 1.58 , mucho más rápido de lo boost::to_upper_copy<char*, std::string>()que hace una estupidez dynamic_castpor cada personaje.
@a `mediante^ 32.