Les plages alphabétiques minuscules et majuscules ne traversent pas une %32
limite "d'alignement" dans le système de codage ASCII.
C'est pourquoi le bit 0x20
est la seule différence entre les versions majuscules / minuscules d'une même lettre.
Si ce n'était pas le cas, vous auriez besoin d'ajouter ou de soustraire 0x20
, pas seulement de basculer, et pour certaines lettres, il y aurait un report pour inverser d'autres bits supérieurs. (Et il n'y aurait pas une seule opération qui pourrait basculer, et vérifier les caractères alphabétiques en premier lieu serait plus difficile car vous ne pourriez pas | = 0x20 pour forcer lcase.)
Astuces connexes ASCII uniquement: vous pouvez rechercher un caractère alphabétique ASCII en forçant les minuscules avec c |= 0x20
puis en vérifiant si (non signé) c - 'a' <= ('z'-'a')
. Donc, juste 3 opérations: OU + SUB + CMP contre une constante 25. Bien sûr, les compilateurs savent comment optimiser (c>='a' && c<='z')
en asm comme ça pour vous , donc au plus vous devriez faire la c|=0x20
partie vous-même. Il est plutôt gênant de faire tout le cast nécessaire vous-même, en particulier pour contourner les promotions entières par défaut à signées 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
Voir aussi Convertir une chaîne en C ++ en majuscules (chaîne SIMD toupper
pour ASCII uniquement, masquant l'opérande pour XOR à l'aide de cette vérification.)
Et aussi Comment accéder à un tableau de caractères et changer les lettres minuscules en majuscules, et vice versa
(C avec les intrinsèques SIMD, et scalaire x86 asm case-flip pour les caractères alphabétiques ASCII, en laissant les autres inchangés.)
Ces astuces ne sont généralement utiles que si vous optimisez manuellement certains traitements de texte avec SIMD (par exemple SSE2 ou NEON), après avoir vérifié qu'aucun des char
s dans un vecteur n'a son ensemble de bits haut. (Et donc aucun des octets ne fait partie d'un codage UTF-8 multi-octets pour un seul caractère, qui peut avoir différents inverses majuscules / minuscules). Si vous en trouvez, vous pouvez revenir au scalaire pour ce bloc de 16 octets ou pour le reste de la chaîne.
Il existe même certains paramètres régionaux où toupper()
ou tolower()
sur certains caractères de la plage ASCII produisent des caractères en dehors de cette plage, notamment le turc où I ↔ ı et İ ↔ i. Dans ces paramètres régionaux, vous auriez besoin d'une vérification plus sophistiquée, ou probablement de ne pas essayer du tout d'utiliser cette optimisation.
Mais dans certains cas, vous êtes autorisé à assumer ASCII au lieu de UTF-8, par exemple les utilitaires Unix avec LANG=C
(la locale POSIX), pas en_CA.UTF-8
ou quoi que ce soit.
Mais si vous pouvez vérifier que c'est sûr, vous pouvez toupper
des chaînes de longueur moyenne beaucoup plus rapidement que d'appeler toupper()
dans une boucle (comme 5x), et pour la dernière fois, j'ai testé avec Boost 1.58 , beaucoup plus rapide que boost::to_upper_copy<char*, std::string>()
ce qui fait un stupide dynamic_cast
pour chaque caractère.
@
en `en utilisant^ 32
.