Convertir une chaîne en C++ en majuscules

comment convertir une chaîne en majuscules. Les exemples que j'ai trouvés à partir de googling n'ont affaire qu'à des caractères.

224
demandé sur Tshepang 2009-04-09 21:38:23

26 réponses

algorithmes de Boost string:

#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");
195
répondu Tony Edgecombe 2015-05-14 03:06:54
#include <algorithm>
#include <string>

std::string str = "Hello World";
std::transform(str.begin(), str.end(),str.begin(), ::toupper);
414
répondu Pierre 2009-04-09 21:11:16

à Court de solution à l'aide de C++11 et toupper().

for (auto & c: str) c = toupper(c);
67
répondu Thanasis Papoutsidakis 2013-07-23 09:49:22
struct convert {
   void operator()(char& c) { c = toupper((unsigned char)c); }
};

// ... 
string uc_str;
for_each(uc_str.begin(), uc_str.end(), convert());

Note: quelques problèmes avec la solution supérieure:

21.5 Null séquence utilitaires

le contenu de ces en-têtes doit être le même que celui des en-têtes de bibliothèque standard C , , , , et < stdlib.h.[ >..]

  • ce qui signifie que le cctype les membres peuvent très bien être des macros ne convenant pas à une consommation directe dans les algorithmes standards.

  • un autre problème avec le même exemple est qu'il ne lance pas l'argument ou ne vérifie pas que ce n'est pas négatif; ceci est particulièrement dangereux pour les systèmes où char est signé. (La raison étant: si ceci est implémenté comme une macro, il utilisera probablement une table de recherche et vos index d'arguments dans cette table. Un indice négatif, vous donnera UB.)

27
répondu dirkgently 2014-08-29 21:22:58

avez-vous de l'ASCII ou des caractères Internationaux dans les chaînes?

si c'est le dernier cas," majuscule " n'est pas si simple, et cela dépend de l'alphabet utilisé. Il existe des alphabets bicaméraux et unicaméraux. Seulement bicaméral alphabets 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 le soi-disant cas de titre . Cela signifie que seulement le premier le caractère (D) est changé.

je vous suggère de regarder dans ICU , et la différence entre les cas simples et les cas complets correspondances. Cela pourrait aider:

http://userguide.icu-project.org/transforms/casemappings

20
répondu Milan Babuškov 2009-04-09 17:58:58
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;
}
18
répondu user648545 2016-06-24 03:56:22

ce problème est vectorisable avec SIMD pour le jeu de caractères ASCII.


comparaisons D'accélération:

des 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 (mélange de minuscules et de non-minuscules ASCII), converti en boucle 40M fois (sans lining de fichier croisé, de sorte que le compilateur ne peut pas optimiser ou hisser tout cela hors de boucle.) La même source et les mêmes tampons, donc aucun effet de mémoire/cache de malloc: les données sont chaudes dans le cache L1 tout le temps, et nous sommes purement CPU-bound.

  • boost::to_upper_copy<char*, std::string>() : 198.0 s . Oui, Boost 1.58 sur Ubuntu 15.10 est vraiment si lent. J'ai profilé et simple-pas le asm dans un débogueur, et c'est vraiment, vraiment mauvais: il y a un dynamic_cast d'une variable locale happening per personnage!!! (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 l'autre forme de to_upper_copy optimise mieux, mais je pense qu'il sera toujours new / malloc espace pour la copie, il est donc plus difficile de tester. Peut-être que quelque chose que j'ai fait diffère d'un cas d'utilisation normale, et peut-être g++ normalement arrêté peut hisser la configuration locale des trucs qui sortent de la boucle du personnage. Ma lecture en boucle d'un std::string et l'écriture à un char dstbuf[4096] a du sens pour le test.

  • boucle appelant glibc toupper : 6,67 s (ne vérifiant pas le résultat int pour les multi-octets UTF-8 potentiels, cependant. C'est important pour le turc.)

  • boucle ASCII seulement: 8,79 s (ma version de base pour les résultats dessous. Apparemment, une recherche de table est plus rapide qu'un cmov , avec la table chaude en L1 de toute façon.
  • ASCII-seulement auto-vectorisé: 2.51 s . (120 chars est à mi-chemin entre le pire et le meilleur cas, voir ci-dessous)
  • ASCII-uniquement vectorisé manuellement: 1,35 s

Voir aussi cette question à propos de toupper() être lent sur Windows quand une locale est définie .


j'ai été choqué que Boost est un ordre de grandeur plus lent que les autres options. J'ai vérifié deux fois que le -O3 était activé, et j'ai même demandé à l'asm de voir ce qu'il faisait. C'est presque exactement la même vitesse avec clang++ 3.8. Il a d'énormes au-dessus à l'intérieur de la boucle de caractère. Le résultat perf record / report (pour l'événement cycles 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% ...

Autovectorization

Gcc et clang ne vont auto-vectoriser 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 de strlen ne seront pas autovectorisées.)

ainsi, pour des cordes assez petites pour s'insérer dans le cache, nous obtenons une accélération significative pour les cordes ~128 caractères de long de faire strlen d'abord. 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;
}

N'importe quelle libc décente aura un strlen efficace qui est beaucoup plus rapide que la boucle d'un octet à la fois, donc séparément vectorisés strlen et les boucles de toupper sont plus rapides.

ligne de base: une boucle qui vérifie une terminaison 0 à la volée.

temps pour itérations 40M, sur un Core2 (Merom) 2,4 GHz. gcc 5.2 -O3 -march=native . (Ubuntu 15.10). dst != src (donc nous faisons une copie), mais ils ne se chevauchent pas (et ne sont pas à proximité). Les deux sont alignés.

  • 15 chaîne de caractères: ligne de base: 1,08 S. autovec: 1.34 s
  • 16 chaîne de caractères: ligne de base: 1.16 S. autovec: 1.52 s
  • 127 chaîne de caractères: ligne de base: 8,91 S. autovec: 2.98 s / / non-vector cleanup dispose de 15 chars à traiter
  • 128 chaîne de caractères: baseline: 9.00 S. autovec: 2.06 s
  • 129 chaîne de char: base de référence: 9.04 s. autovec: 2.07 s // le nettoyage non vectoriel a 1 Carot à traiter

Certains résultats sont un peu différents, avec clang.

La microbenchmark boucle qui appelle la fonction est dans un fichier séparé. Sinon, il s'enroule et strlen() est hissé hors de la boucle, et il court beaucoup plus vite, esp. pour 16 chaînes de caractères (0.187 s).

cela a l'avantage majeur que gcc peut auto-vectoriser pour n'importe quelle architecture, mais le principal l'inconvénient est qu'il est plus lent pour le cas habituellement-commun de petites cordes.


Donc, il y a de grandes accélérations, mais le compilateur auto-vectorisation de ne pas faire le grand code, esp. pour nettoyer les 15 derniers personnages.

vectorisation manuelle avec SSE intrinsics:

basé sur ma fonction case-flip qui inverse le cas de chaque caractère alphabétique. Il faut avantage du "non-signé comparer trick", où vous pouvez faire low < a && a <= high avec une seule comparaison non signée par le déplacement de gamme, de sorte que toute valeur inférieure à low enveloppements à une valeur qui est supérieure à high . (Cela fonctionne si low et high ne sont pas trop éloignés.)

SSE a seulement un Comparer-plus signé, mais nous pouvons toujours utiliser le " non signé comparer" truc de l'aire de déplacement vers le bas de la signature de la gamme: Soustraire 'a'+128, de sorte que le les caractères alphabétiques vont de -128 -128 à+25 (-128+'z'-'a')

notez que l'addition de 128 et la soustraction de 128 sont la même chose pour les entiers de 8bit. Il n'y a nulle part où aller pour le carry, donc il est juste xor (carryless add), en retournant le haut bit.

#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 dans une boucle pour traiter une chaîne entière. Puisque nous ciblons déjà SSE2, nous pouvons faire un contrôle de fin de chaîne vectorisé à la même temps.

nous pouvons également faire beaucoup mieux pour le" nettoyage " des derniers bytes up-to-15 laissés après avoir fait des vecteurs de 16B: Upper-casing est idempotent, donc re-traitement de certains bytes d'entrée est très bien. Nous faisons une charge non alignée du dernier 16B de la source, et la stockons dans le tampon le plus dest chevauchant le dernier 16b de la boucle.

la seule fois où cela ne fonctionne pas , c'est quand toute la chaîne est sous 16B: même quand dst=src , non-atomique read-modify-write est pas la même chose que de ne pas toucher certains octets du tout, et peut casser le code multithreaded.

nous avons une boucle scalaire pour cela, et aussi d'obtenir src aligné. Puisque nous ne savons pas où se trouve le 0 final, une charge non alignée de src pourrait se croiser dans la page suivante et segfault. Si nous avons besoin de n'importe quel Byte dans un morceau aligné 16B, il est toujours sûr de charger l'ensemble du morceau aligné 16B.

source: 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 '"151930920"' 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 '"151930920"'

    // 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 "151930920"
            _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 itérations 40M, sur un Core2 (Merom) 2,4 GHz. gcc 5.2 -O3 -march=native . (Ubuntu 15.10). dst != src (donc nous faisons une copie), mais ils ne se chevauchent pas (et ne sont pas à proximité). Les deux sont alignés.

  • 15 chaîne de caractères: ligne de base: 1,08 S. autovec: 1.34 S. manuel: 1.29 s
  • 16 chaîne de caractères: ligne de base: 1.16 S. autovec: 1.52 S. manuel: 0.335 s
  • 31 chaîne de char: manuel: 0.479 s
  • 127 chaîne de caractères: ligne de base: 8,91 S. autovec: 2.98 S. manuel: 0,925 s
  • 128 chaîne de caractères: baseline: 9.00 S. autovec: 2.06 S. manuel: 0,931 s
  • 129 chaîne de char: base de référence: 9.04 s. autovec: 2.07 s. manuel: 1.02 s

(en fait chronométré avec _mm_store dans la boucle, pas _mm_storeu , parce que storeu est plus lent sur Merom même lorsque l'adresse est aligné. C'est bien à Nehalem et plus tard. J'ai aussi laissé le code tel quel pour l'instant, au lieu de corriger l'échec de copier le 0 terminal dans certains cas, parce que je ne veux pas tout re-time.)

donc pour des cordes courtes plus longues que 16B, c'est dramatiquement plus rapide que Auto-vectorisé. Les longueurs un-moins-que-un-vecteur-largeur ne présentent pas de problème. Ils peuvent être un problème lors de l'exploitation sur place, en raison d'un stalle de transit. (Mais notez qu'il est encore possible de traiter notre propre sortie, plutôt que l'entrée originale, parce que toupper est idempotent).

il y a beaucoup de place pour ajuster cela pour différents cas d'utilisation, en fonction de ce que le code environnant veut, et la microarchitecture cible. Obtenir que le compilateur émette du code sympa pour la partie nettoyage est délicat. Utiliser ffs(3) (qui compile à bsf ou tzcnt sur x86) semble être bon, mais évidemment que bit a besoin d'une nouvelle réflexion puisque je j'ai remarqué un bug Après avoir écrit la plupart de cette réponse (voir les commentaires de FIXME).

des vitesses vectorielles pour des cordes encore plus petites peuvent être obtenues avec des charges/emmagasins movq ou movd . Personnalisez au besoin pour votre étui.


UTF-8:

nous pouvons détecter quand notre Vecteur a n'importe quels bytes avec le réglage de haut bit, et dans ce cas, retomber à un utf-8 scalaire conscient boucle pour ce vecteur. Le point dst peut avancer d'une quantité différente que le pointeur src , mais une fois que nous sommes de retour à un pointeur aligné src , nous allons encore faire des magasins vectoriels non alignés à dst .

pour le texte qui est UTF-8, mais se compose principalement du sous-ensemble ASCII de UTF-8, cela peut être bon: haute performance dans le cas commun avec un comportement correct dans tous les cas. Quand il ya beaucoup de non-ASCII, il sera probablement pire que rester dans la boucle scalaire consciente UTF-8 tout le temps, cependant.

Faire de l'anglais plus rapidement, au détriment des autres langues n'est pas l'avenir de la décision si la baisse est significative.


Locale-conscient:

dans le local Turc ( tr_TR ), le résultat correct de toupper('i') est 'İ' (U0130), pas 'I' (ASCII simple). Voir commentaires de Martin Bonner sur une question à propos de tolower() étant lent sur Windows.

nous pouvons également vérifier pour une liste d'exceptions et de repli sur scalar là-bas, comme pour les caractères D'entrée UTF8 multi-octets.

avec cette grande complexité, SSE4.2 PCMPISTRM ou quelque chose pourrait être capable de faire beaucoup de nos vérifications en une seule fois.

15
répondu Peter Cordes 2017-05-23 12:26:35

Le plus rapide si vous utilisez uniquement 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 fonctionne plus rapidement mais seulement 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++.

15
répondu Luca C. 2018-02-07 13:27:24

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);
11
répondu Byron 2014-06-15 02:31:40
//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;
}
9
répondu David 2010-08-01 04:24:06
#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 donnera de meilleurs résultats que toutes les réponses qui utilisent la fonction toupper globale, et c'est probablement ce que boost::to_upper fait en dessous.

c'est parce que ::toupper doit chercher la locale - parce qu'elle a pu être changée par un fil différent - pour chaque invocation, alors qu'Ici seul l'appel à la locale() a cette pénalité. Et chercher le lieu implique généralement de prendre une serrure.

Cela fonctionne aussi avec C++98 après avoir remplacé l'auto, utilisez la nouvelle str non-const.de données(), et ajouter un espace de briser le modèle de clôture ( "> > ""> > " ) 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());
9
répondu Glen Knowles 2016-10-08 01:04:10

les travaux suivants 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);
}
9
répondu Pabitra Dash 2018-02-03 15:28:17
inline void strtoupper(char* str)
{
    while (*str)
    {
        *str = toupper((unsigned char)*str);
        str++;
    }
}
9
répondu k3a 2018-04-03 10:13:45
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 );
7
répondu bayda 2009-04-09 17:55:02
std::string value;
for (std::string::iterator p = value.begin(); value.end() != p; ++p)
    *p = toupper(*p);
4
répondu Dmitriy Yurchenko 2011-02-19 21:08:22

essayez la fonction toupper() ( #include <ctype.h> ). il accepte les caractères comme arguments, les chaînes sont composées de caractères, donc vous devrez itérer sur chaque caractère individuel qui une fois mis ensemble comprennent la chaîne

2
répondu zmf 2010-03-09 21:43:51

voici le dernier code avec C++11

std::string cmd = "Hello World";
for_each(cmd.begin(), cmd.end(), [](char& in){ in = ::toupper(in); });
2
répondu user2787620 2013-12-27 06:46:12

pas sûr qu'il y est une fonction intégrée. Essayez ceci:

comprend le ctype.H ou cctype bibliothèques, ainsi que le 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
}
0
répondu Brandon Stewart 2009-04-09 17:54:44

Ma solution (compensation de 6 bits pour l'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++;
    }
}
0
répondu 421 2018-01-24 02:35:32

toutes ces solutions sur cette page sont plus dures qu'elles ne doivent l'être.

Faire

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 de caractères n'utilisez pas string.size() comme votre testeur réel, très salissant et peuvent causer des problèmes. puis. la boucle la plus basique for .

remember string size renvoie le délimiteur aussi alors utilisez < et non <= dans votre test de boucle.

sortie être: une chaîne que vous voulez convertir

-1
répondu secret 2012-10-26 10:09:47

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;
}
-1
répondu hkBattousai 2013-08-18 17:23:20

si vous n'êtes concerné que par les caractères 8 bits (ce que toutes les autres réponses sauf Milan Babuškov supposent aussi), vous pouvez obtenir la vitesse la plus rapide en générant une table de recherche au moment de la compilation en utilisant metaprogrammation. Sur ideone.com ceci exécute 7x plus vite que la fonction de bibliothèque et 3x plus vite qu'une version écrite à la main ( http://ideone.com/sb1Rup ). Il est également personnalisable à travers 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 la façon dont il fonctionne me permettent de brancher sans vergogne mon blog: http://metaporky.blogspot.de/2014/07/part-4-generating-look-up-tables-at.html

-1
répondu odinthenerd 2014-07-31 13:26:06
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;
}
-1
répondu Ronny Gunawan 2015-04-16 18:46:15

cette fonction C++ renvoie toujours la chaîne de caractères supérieure...

#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;
}
-1
répondu Awais Jameel 2018-08-19 18:07:13

j'utilise cette solution. Je sais que vous n'êtes pas censé modifier la zone de données.... mais je pense que c'est surtout pour les bogues de dépassement de tampon et le caractère null.... les douilles supérieures 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]);
    }
}
-3
répondu Erik Aronesty 2012-05-02 20:25:45

dans toutes les machines que j'ai testées, c'était plus rapide. Peut-être parce qu'il n'est pas concerné avec un très large éventail de personnages. Ou parce que l'utilisation de switch () fait une table de saut, ne savent pas comment cela fonctionne dans l'assemblage ... sachez juste que c'est plus rapide: p

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;
}
-7
répondu osmano807 2010-03-10 01:59:53