Comment pourrait-on convertir une chaîne en majuscules. Les exemples que j'ai trouvés sur Google ne concernent que les caractères.
Comment pourrait-on convertir une chaîne en majuscules. Les exemples que j'ai trouvés sur Google ne concernent que les caractères.
Réponses:
Boost algorithmes de chaîne:
#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()
peut être implémenté comme une macro. Cela peut provoquer un problème.
toupper
. Des idées?
Solution courte utilisant C ++ 11 et toupper ().
for (auto & c: str) c = toupper(c);
c
de const char
type (de auto
)? Si c'est le cas, vous ne pouvez pas l'affecter (en raison d'une const
partie) à ce qui est retourné par toupper(c)
.
c
doit être casté pour unsigned char
que cela soit corrigé.
struct convert {
void operator()(char& c) { c = toupper((unsigned char)c); }
};
// ...
string uc_str;
for_each(uc_str.begin(), uc_str.end(), convert());
Remarque: quelques problèmes avec la meilleure solution:
21.5 Utilitaires de séquence à terminaison nulle
Le contenu de ces en-têtes doit être le même que les en-têtes de la bibliothèque C standard <ctype.h>, <wctype.h>, <string.h>, <wchar.h> et <stdlib.h> [...]
Ce qui signifie que les cctype
membres peuvent bien être des macros non adaptées à la consommation directe dans les algorithmes standards.
Un autre problème avec le même exemple est qu'il ne jette pas l'argument ni ne vérifie que ce n'est pas négatif; ceci est particulièrement dangereux pour les systèmes où plain char
est signé. (La raison en est: si elle est implémentée en tant que macro, elle utilisera probablement une table de recherche et vos arguments dans cette table. Un index négatif vous donnera UB.)
Ce problème est vectorisable avec SIMD pour le jeu de caractères ASCII.
Tests préliminaires avec x86-64 gcc 5.2 -O3 -march=native
sur un Core2Duo (Merom). La même chaîne de 120 caractères (ASCII mixte en minuscules et non en minuscules), convertie en boucle 40 millions de fois (sans insertion de fichier croisé, de sorte que le compilateur ne peut pas l'optimiser ou le retirer de la boucle). Mêmes tampons source et dest, donc pas de surcharge malloc ou d'effets mémoire / cache: les données sont chaudes dans le cache L1 tout le temps, et nous sommes purement liés au CPU.
boost::to_upper_copy<char*, std::string>()
: 198,0 s . Oui, Boost 1.58 sur Ubuntu 15.10 est vraiment aussi lent. J'ai profilé et fait une seule étape dans un débogueur, et c'est vraiment, vraiment mauvais: il y a un dynamic_cast d'une variable locale qui se produit par caractère !!! (dynamic_cast prend plusieurs appels à strcmp). Cela se produit avec LANG=C
et avec LANG=en_CA.UTF-8
.
Je n'ai pas testé en utilisant un RangeT autre que std :: string. Peut-être que l'autre forme d'to_upper_copy
optimise mieux, mais je pense que ce sera toujours new
/ malloc
espace pour la copie, donc c'est plus difficile à tester. Peut-être que quelque chose que j'ai fait diffère d'un cas d'utilisation normal, et peut-être que g ++ est normalement arrêté peut hisser la configuration locale hors de la boucle par caractère. Ma lecture en boucle d'un std::string
et l'écriture vers un char dstbuf[4096]
est logique pour les tests.
boucle appelant la glibc toupper
: 6,67 s (ne vérifie pas le int
résultat pour un potentiel UTF-8 multi-octets, cependant. Cela est important pour le turc.)
cmov
, avec la table chaude en L1 de toute façon.Voir aussi cette question sur la toupper()
lenteur sous Windows lorsqu'un paramètre régional est défini .
J'ai été choqué que Boost soit un ordre de grandeur plus lent que les autres options. J'ai revérifié que j'avais -O3
activé, et j'ai même fait un pas pour voir ce qu'il faisait. C'est presque exactement la même vitesse avec clang ++ 3.8. Il a une énorme surcharge à l'intérieur de la boucle par caractère. Le résultat perf record
/ report
(pour l' cycles
événement perf) est:
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 et clang ne vectoriseront automatiquement les boucles que lorsque le nombre d'itérations est connu avant la boucle. (c'est-à-dire que les boucles de recherche comme l'implémentation plain-C de strlen
ne seront pas autovectorisées.)
Ainsi, pour les chaînes suffisamment petites pour tenir dans le cache, nous obtenons une accélération significative pour les chaînes ~ 128 caractères longtemps avant de strlen
commencer. Cela ne sera pas nécessaire pour les chaînes de longueur explicite (comme 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;
}
Toute libc décente aura une efficacité strlen
beaucoup plus rapide que de boucler un octet à la fois, donc les boucles strlen et toupper vectorisées séparées sont plus rapides.
Ligne de base: une boucle qui vérifie un 0 se terminant à la volée.
Temps pour les itérations 40M, sur un Core2 (Merom) 2,4 GHz. gcc 5.2 -O3 -march=native
. (Ubuntu 15.10). dst != src
(nous faisons donc une copie), mais ils ne se chevauchent pas (et ne sont pas à proximité). Les deux sont alignés.
Certains résultats sont un peu différents avec clang.
La boucle de microbenchmark qui appelle la fonction se trouve dans un fichier séparé. Sinon, il s'aligne et strlen()
se hisse hors de la boucle, et il fonctionne considérablement plus vite, esp. pour 16 chaînes de caractères (0,187 s).
Cela a le principal avantage que gcc peut le vectoriser automatiquement pour n'importe quelle architecture, mais l'inconvénient majeur qu'il est plus lent pour le cas généralement courant des petites chaînes.
Il y a donc de grandes accélérations, mais la vectorisation automatique du compilateur ne fait pas un excellent code, en particulier. pour le nettoyage des 15 derniers caractères maximum.
Basé sur ma fonction de retournement de casse qui inverse la casse de chaque caractère alphabétique. Il tire parti de "l'astuce de comparaison non signée", où vous pouvez faire low < a && a <= high
une seule comparaison non signée par décalage de plage, de sorte que toute valeur inférieure à se low
termine par une valeur supérieure à high
. (Cela fonctionne si low
et high
ne sont pas trop éloignés.)
SSE a uniquement une comparaison signée supérieure, mais nous pouvons toujours utiliser l'astuce "comparaison non signée" en décalant la plage vers le bas de la plage signée: soustrayez 'a' + 128, de sorte que les caractères alphabétiques varient de -128 à -128 +25 (-128 + 'z' - 'a')
Notez que l'ajout de 128 et la soustraction de 128 sont la même chose pour les entiers 8 bits. Il n'y a nulle part où aller pour le porter, donc c'est juste xor (add sans porter), renversant le bit haut.
#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
}
Étant donné cette fonction qui fonctionne pour un vecteur, nous pouvons l'appeler en boucle pour traiter une chaîne entière. Puisque nous ciblons déjà SSE2, nous pouvons effectuer une vérification de fin de chaîne vectorisée en même temps.
Nous pouvons également faire beaucoup mieux pour le "nettoyage" des derniers jusqu'à-15 octets restants après avoir fait des vecteurs de 16B: le boîtier supérieur est idempotent, donc le retraitement de certains octets d'entrée est très bien. Nous effectuons un chargement non aligné du dernier 16B de la source et le stockons dans le tampon dest chevauchant le dernier magasin 16B de la boucle.
La seule fois où cela ne fonctionne pas, c'est lorsque la chaîne entière est inférieure à 16B: Même lorsque dst=src
, la lecture-modification-écriture non atomique n'est pas la même chose que de ne pas toucher du tout certains octets, et peut casser le code multithread.
Nous avons une boucle scalaire pour cela, et aussi pour nous src
aligner. Puisque nous ne savons pas où se terminera le 0, une charge non alignée src
pourrait traverser la page suivante et segfault. Si nous avons besoin d'octets dans un bloc 16B aligné, il est toujours sûr de charger l'ensemble du bloc 16B aligné.
Source complète: dans 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;
}
Temps pour les itérations 40M, sur un Core2 (Merom) 2,4 GHz. gcc 5.2 -O3 -march=native
. (Ubuntu 15.10). dst != src
(nous faisons donc une copie), mais ils ne se chevauchent pas (et ne sont pas à proximité). Les deux sont alignés.
(En fait chronométré avec _mm_store
dans la boucle, non _mm_storeu
, car storeu est plus lent sur Merom même lorsque l'adresse est alignée. C'est bien sur Nehalem et plus tard. J'ai également laissé le code tel quel pour le moment, au lieu de corriger l'échec de la copie le 0 final dans certains cas, parce que je ne veux pas tout re-chronométrer.)
Ainsi, pour les chaînes courtes supérieures à 16B, cela est considérablement plus rapide que la vectorisation automatique. Les longueurs d'une largeur inférieure à un vecteur ne posent pas de problème. Ils peuvent être un problème lors du fonctionnement sur place, en raison d'un blocage de transfert de magasin. (Mais notez qu'il est toujours correct de traiter notre propre sortie, plutôt que l'entrée d'origine, car toupper est idempotent).
Il y a beaucoup de possibilités pour régler cela pour différents cas d'utilisation, selon ce que le code environnant veut et la microarchitecture cible. Il est difficile d'obtenir le compilateur pour émettre du code agréable pour la partie de nettoyage. Utiliser ffs(3)
(qui se compile en bsf ou tzcnt sur x86) semble être bon, mais évidemment ce bit a besoin d'être repensé puisque j'ai remarqué un bogue après avoir écrit la plupart de cette réponse (voir les commentaires FIXME).
Des accélérations vectorielles pour des chaînes encore plus petites peuvent être obtenues avec movq
ou des movd
charges / stockages. Personnalisez au besoin pour votre cas d'utilisation.
Nous pouvons détecter quand notre vecteur a des octets avec le bit le plus élevé et, dans ce cas, revenir à une boucle scalaire prenant en charge utf-8 pour ce vecteur. Le dst
point peut avancer d'une quantité différente de celle du src
pointeur, mais une fois que nous revenons à un src
pointeur aligné , nous ne faisons que stocker des vecteurs non alignés dst
.
Pour le texte qui est UTF-8, mais qui se compose principalement du sous-ensemble ASCII d'UTF-8, cela peut être bon: hautes performances dans le cas commun avec un comportement correct dans tous les cas. Quand il y a beaucoup de non-ASCII, ce sera probablement pire que de rester dans la boucle consciente scalaire UTF-8, cependant.
Rendre l'anglais plus rapide au détriment des autres langues n'est pas une décision d'avenir si l'inconvénient est significatif.
Dans les paramètres régionaux turcs ( tr_TR
), le résultat correct toupper('i')
est 'İ'
(U0130) et non 'I'
(ASCII ordinaire). Voir les commentaires de Martin Bonner sur une question concernant la tolower()
lenteur sous Windows.
Nous pouvons également rechercher une liste d'exceptions et un retour à scalaire, comme pour les caractères d'entrée UTF8 multi-octets.
Avec une telle complexité, SSE4.2 PCMPISTRM
ou quelque chose pourrait être capable de faire beaucoup de nos vérifications en une seule fois.
Avez-vous des caractères ASCII ou internationaux dans les chaînes?
Si c'est le dernier cas, "majuscule" n'est pas aussi simple que cela, et cela dépend de l'alphabet utilisé. Il existe des alphabets bicaméraux et unicaméraux. Seuls les alphabets bicaméraux ont des caractères différents pour les majuscules et les minuscules. En outre, il existe des caractères composites, comme la lettre majuscule latine 'DZ' (\ u01F1 'DZ') qui utilisent ce qu'on appelle la casse du titre . Cela signifie que seul le premier caractère (D) est modifié.
Je vous suggère de vous pencher sur l' ICU et de faire la différence entre les mappages de cas simples et complets. Cela pourrait aider:
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;
}
**
après les paramètres de la première solution?
**
c'est une faute de frappe d'essayer d'utiliser une police en gras dans la syntaxe du code.
toupper
est appelé avec des nombres négatifs.
Ce qui suit fonctionne pour moi.
#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
est appelé avec des nombres négatifs.
Utilisez un 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);
Le plus rapide si vous n'utilisez que des caractères ASCII :
for(i=0;str[i]!=0;i++)
if(str[i]<='z' && str[i]>='a')
str[i]-=32;
Veuillez noter que ce code s'exécute plus rapidement mais ne fonctionne que sur ASCII et n'est pas une solution "abstraite".
Si vous avez besoin de solutions UNICODE ou de solutions plus conventionnelles et abstraites, optez pour d'autres réponses et travaillez avec des méthodes de chaînes C ++.
C++
, mais vous avez écrit une C
réponse ici. (Je ne suis pas un des downvoters.)
'
?
Tant que vous êtes bien avec ASCII uniquement et que vous pouvez fournir un pointeur valide vers la mémoire RW, il existe une ligne simple et très efficace en C:
void strtoupper(char* str)
{
while (*str) *(str++) = toupper((unsigned char)*str);
}
C'est particulièrement bon pour les chaînes simples comme les identifiants ASCII que vous souhaitez normaliser dans la même casse de caractères. Vous pouvez ensuite utiliser le tampon pour construire une instance 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 ...
. Il n'y a également aucune bonne raison de le rendre si difficile à lire. Cela copie également la chaîne en premier puis la boucle. @ La réponse de Luke est meilleure à certains égards, sauf pour ne pas profiter des 'a'
constantes de caractère.
#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());
Cela fonctionnera mieux que toutes les réponses qui utilisent la fonction globale toupper, et c'est probablement ce que boost :: to_upper fait en dessous.
C'est parce que :: toupper doit rechercher les paramètres régionaux - car ils peuvent avoir été modifiés par un thread différent - pour chaque appel, alors qu'ici seul l'appel à locale () a cette pénalité. Et rechercher les paramètres régionaux implique généralement de prendre un verrou.
Cela fonctionne également avec C ++ 98 après avoir remplacé l'auto, l'utilisation de la nouvelle str.data () non const et ajouté un espace pour interrompre la fermeture du modèle (">>" à ">>") comme ceci:
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
et back_inserter
(pour que la chaîne ne soit copiée qu'une seule fois). 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
est appelé avec des nombres négatifs.
essayez la toupper()
fonction ( #include <ctype.h>
). il accepte les caractères comme arguments, les chaînes sont composées de caractères, vous devrez donc parcourir chaque caractère individuel qui, une fois mis en place, comprend la chaîne
toupper
est appelée avec des nombres négatifs. Vous auriez dû mentionner le casting nécessaire pour unsigned char
.
Voici le dernier code avec C ++ 11
std::string cmd = "Hello World";
for_each(cmd.begin(), cmd.end(), [](char& in){ in = ::toupper(in); });
toupper
est appelé avec des nombres négatifs.
La réponse de @dirkgently est très inspirante, mais je tiens à souligner qu'en raison de l'inquiétude indiquée ci-dessous,
Comme toutes les autres fonctions de, le comportement de std :: toupper n'est pas défini si la valeur de l'argument n'est ni représentable comme caractère non signé ni égale à EOF. Pour utiliser ces fonctions en toute sécurité avec des caractères simples (ou des caractères signés), l'argument doit d'abord être converti en caractères non signés
Référence : std :: toupper
l'utilisation correcte de std::toupper
devrait être:
#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;
}
Production:
Hello world!
HELLO WORLD!
pas sûr qu'il y ait une fonction intégrée. Essaye ça:
Incluez les bibliothèques ctype.h OU cctype, ainsi que stdlib.h dans le cadre des directives du préprocesseur.
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
est appelé avec des nombres négatifs.
Ma solution (effacer le 6e bit pour alpha):
#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
est appelé avec des nombres négatifs.
TOUTES ces solutions sur cette page sont plus difficiles qu'elles ne devraient l'être.
Faites ceci
RegName = "SomE StRing That you wAnt ConvErTed";
NameLength = RegName.Size();
for (int forLoop = 0; forLoop < NameLength; ++forLoop)
{
RegName[forLoop] = tolower(RegName[forLoop]);
}
RegName
est votre string
. Obtenez votre taille de chaîne ne pas utiliser string.size()
comme testeur réel, très désordonné et peut causer des problèmes. puis. la for
boucle la plus basique .
rappelez-vous que la taille de la chaîne renvoie également le délimiteur, utilisez donc <et non <= dans votre test de boucle.
la sortie sera: une chaîne que vous souhaitez convertir
tolower
boucles simples , et la plupart d'entre elles utilisent des noms de variables de boucle standard comme i
, pas les étranges forLoop
.
Sans utiliser de bibliothèques:
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 vous ne vous préoccupez que des caractères 8 bits (ce que toutes les autres réponses sauf Milan Babuškov supposent également), vous pouvez obtenir la vitesse la plus rapide en générant une table de recherche au moment de la compilation à l'aide de la métaprogrammation. Sur ideone.com, cela fonctionne 7 fois plus vite que la fonction de bibliothèque et 3 fois plus vite qu'une version manuscrite ( http://ideone.com/sb1Rup ). Il est également personnalisable grâce à des traits sans ralentissement.
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);
}
avec cas d'utilisation:
std::transform(in.begin(),in.end(),out.begin(),tableToUpper);
Pour une description en profondeur (plusieurs pages) de son fonctionnement, permettez-moi de brancher sans vergogne mon 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;
}
Cette fonction c ++ renvoie toujours la chaîne majuscule ...
#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;
}
J'utilise cette solution. Je sais que vous n'êtes pas censé modifier cette zone de données .... mais je pense que c'est principalement pour les bogues de dépassement de tampon et le caractère nul .... les choses majuscules ne sont pas les mêmes.
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
- quelle zone de données n'êtes-vous pas censé modifier?
str[i] = toupper(str[i]);
parfaitement fine (enfin, pas parfaitement fine, mais elle corrige la plupart des problèmes).
::toupper
on suppose très probablement ASCII.