Come si può convertire una stringa in maiuscolo. Gli esempi che ho trovato su Google hanno a che fare solo con i caratteri.
Come si può convertire una stringa in maiuscolo. Gli esempi che ho trovato su Google hanno a che fare solo con i caratteri.
Risposte:
Potenzia gli algoritmi delle stringhe:
#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()
può essere implementato come una macro. Ciò può causare un problema.
toupper
. Qualche idea?
Breve soluzione usando C ++ 11 e toupper ().
for (auto & c: str) c = toupper(c);
c
sarebbe di const char
tipo (da auto
)? In tal caso, non è possibile assegnarlo (a causa della const
parte) a ciò che viene restituito toupper(c)
.
c
necessario eseguire il cast unsigned char
per correggere questo.
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 paio di problemi con la soluzione migliore:
21.5 Utilità di sequenza senza terminazione
Il contenuto di queste intestazioni deve essere uguale alle intestazioni della libreria C standard <ctype.h>, <wctype.h>, <string.h>, <wchar.h> e <stdlib.h> [...]
Ciò significa che i cctype
membri potrebbero essere macro non adatte al consumo diretto negli algoritmi standard.
Un altro problema con lo stesso esempio è che non lancia l'argomento né verifica che ciò non sia negativo; questo è particolarmente pericoloso per i sistemi in cui char
è firmato plain . (Il motivo è: se questo è implementato come una macro, probabilmente utilizzerà una tabella di ricerca e il tuo argomento si indicherà in quella tabella. Un indice negativo ti darà UB.)
Questo problema è realizzabile con SIMD per il set di caratteri ASCII.
Test preliminari con x86-64 gcc 5.2 -O3 -march=native
su un Core2Duo (Merom). La stessa stringa di 120 caratteri (ASCII minuscole e non minuscole miste), convertita in un loop 40M volte (senza allineamento tra file, quindi il compilatore non può ottimizzare via o sollevare nulla dal loop). Stessi buffer di origine e dest, quindi nessun sovraccarico malloc o effetti memoria / cache: i dati sono caldi nella cache L1 per tutto il tempo e siamo puramente legati alla CPU.
boost::to_upper_copy<char*, std::string>()
: 198.0s . Sì, Boost 1.58 su Ubuntu 15.10 è davvero così lento. Ho profilato e fatto un singolo passo in avanti in un debugger, ed è davvero pessimo: c'è un Dynamic_cast di una variabile locale in corso per personaggio !!! (dynamic_cast accetta più chiamate su strcmp). Questo succede con LANG=C
e con LANG=en_CA.UTF-8
.
Non ho testato usando un RangeT diverso da std :: string. Forse l'altra forma dito_upper_copy
ottimizza meglio, ma penso che sarà sempre new
/ malloc
spazio per la copia, quindi è più difficile testarlo. Forse qualcosa che ho fatto differisce da un normale caso d'uso, e forse normalmente fermato g ++ può sollevare le cose di configurazione della localizzazione dal ciclo per carattere. Il mio ciclo di lettura da std::string
e scrittura a char dstbuf[4096]
ha senso per i test.
loop che chiama glibc toupper
: 6.67s (non controllando il int
risultato per il potenziale UTF-8 multi-byte, questo è importante per il turco).
cmov
, con la tabella calda in L1 comunque.Vedi anche questa domanda toupper()
sull'essere lento su Windows quando è impostata un'impostazione internazionale .
Sono rimasto scioccato dal fatto che Boost sia un ordine di grandezza più lento delle altre opzioni. Ho ricontrollato che avevo -O3
abilitato e ho anche fatto un singolo passo in avanti per vedere cosa stava facendo. È quasi esattamente la stessa velocità con clang ++ 3.8. Ha un enorme sovraccarico all'interno del ciclo per personaggio. Il risultato perf record
/ report
(per l' cycles
evento perf) è:
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 e clang vettorializzano automaticamente i loop solo quando il conteggio delle iterazioni è noto prima del loop. (ad esempio, i cicli di ricerca come l'implementazione in chiaro di C strlen
non si autovectorizza.)
Pertanto, per le stringhe abbastanza piccole da adattarsi alla cache, otteniamo una notevole velocità per stringhe ~ 128 caratteri lunghi rispetto alla strlen
prima. Ciò non sarà necessario per le stringhe di lunghezza esplicita (come 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;
}
Qualsiasi libc decente avrà un efficiente strlen
che è molto più veloce del looping di un byte alla volta, quindi i circuiti separati e gli anelli di toupper separati sono più veloci.
Linea di base: un ciclo che verifica al volo uno 0 finale.
Tempi per 40 M di iterazioni, su un Core2 (Merom) a 2,4 GHz. gcc 5.2 -O3 -march=native
. (Ubuntu 15.10). dst != src
(quindi ne facciamo una copia), ma non si sovrappongono (e non sono nelle vicinanze). Entrambi sono allineati.
Alcuni risultati sono leggermente diversi con clang.
Il loop microbenchmark che chiama la funzione si trova in un file separato. Altrimenti si allinea e strlen()
viene sollevato fuori dal giro, e corre drasticamente più veloce, esp. per 16 stringhe di caratteri (0,187 s).
Questo ha il grande vantaggio che gcc può auto-vettorializzarlo per qualsiasi architettura, ma il principale svantaggio è che è più lento nel caso comune di stringhe di piccole dimensioni.
Quindi ci sono grandi accelerazioni, ma l'auto-vettorializzazione del compilatore non è un ottimo codice, esp. per la pulizia degli ultimi fino a 15 caratteri.
Basato sulla mia funzione di capovolgimento che inverte il caso di ogni carattere alfabetico. Sfrutta il "trucco comparativo senza segno", in cui è possibile eseguire low < a && a <= high
un singolo confronto senza segno mediante lo spostamento di intervallo, in modo che qualsiasi valore inferiore a quello si low
sovrapponga a un valore maggiore di high
. (Funziona se low
e high
non sono troppo distanti.)
SSE ha solo un confronto con segno maggiore, ma possiamo ancora usare il trucco "confronto senza segno" spostando il range alla fine dell'intervallo con segno: Sottrai 'a' + 128, quindi i caratteri alfabetici vanno da -128 a -128 +25 (-128 + 'z' - 'a')
Si noti che l'aggiunta di 128 e la sottrazione di 128 sono la stessa cosa per numeri interi a 8 bit. Non c'è nessun posto dove andare per il carry, quindi è solo xor (carryless add), lanciando il 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
}
Data questa funzione che funziona per un vettore, possiamo chiamarlo in un ciclo per elaborare un'intera stringa. Dato che stiamo già prendendo di mira SSE2, possiamo eseguire contemporaneamente un controllo vettoriale di fine stringa.
Possiamo anche fare molto meglio per la "pulizia" degli ultimi fino a 15 byte rimasti dopo aver eseguito vettori di 16B: il maiuscolo è idempotente, quindi rielaborare alcuni byte di input va bene. Eseguiamo un carico non allineato degli ultimi 16 B del sorgente e lo memorizziamo nel buffer dest sovrapponendo l'ultimo archivio 16B dal ciclo.
L'unica volta che non funziona è quando l'intera stringa è sotto 16B: Anche quando dst=src
, la lettura-modifica-scrittura non atomica non è la stessa cosa di non toccare affatto alcuni byte e può rompere il codice multithread.
Abbiamo un loop scalare per questo, e anche per src
allinearci. Dato che non sappiamo dove si troverà lo 0 che termina, un carico non allineato src
potrebbe attraversare la pagina successiva e segfault. Se abbiamo bisogno di byte in un blocco 16B allineato, è sempre sicuro caricare l'intero blocco 16B allineato.
Fonte completa: in sintesi .
// 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;
}
Tempi per 40 M di iterazioni, su un Core2 (Merom) a 2,4 GHz. gcc 5.2 -O3 -march=native
. (Ubuntu 15.10). dst != src
(quindi ne facciamo una copia), ma non si sovrappongono (e non sono nelle vicinanze). Entrambi sono allineati.
(In realtà è sincronizzato con _mm_store
nel ciclo, no _mm_storeu
, perché storeu è più lento su Merom anche quando l'indirizzo è allineato. Va bene su Nehalem e versioni successive. Ho anche lasciato il codice così com'è per ora, invece di correggere l'errore di copia lo 0 che termina in alcuni casi, perché non voglio riprogrammare tutto.)
Quindi per stringhe corte più lunghe di 16B, questo è notevolmente più veloce di auto-vettorializzare. Le lunghezze una larghezza inferiore a un vettore non presentano problemi. Potrebbero essere un problema quando si opera sul posto, a causa di uno stallo di inoltro del negozio. (Ma nota che è ancora bene elaborare il nostro output, piuttosto che l'input originale, perché toupper è idempotente).
C'è molto spazio per ottimizzare questo per diversi casi d'uso, a seconda di ciò che vuole il codice circostante e della microarchitettura di destinazione. Far in modo che il compilatore emetta un bel codice per la parte di pulizia è complicato. L'uso ffs(3)
(che si compila in bsf o tzcnt su x86) sembra essere buono, ma ovviamente quel bit ha bisogno di un ripensamento poiché ho notato un bug dopo aver scritto la maggior parte di questa risposta (vedere i commenti FIXME).
Accelerazioni vettoriali per stringhe ancora più piccole possono essere ottenute con movq
o movd
carichi / negozi. Personalizza secondo necessità per il tuo caso d'uso.
Siamo in grado di rilevare quando il nostro vettore ha dei byte con il bit alto impostato e, in tal caso, ricorrere a un loop scalare compatibile con utf-8 per quel vettore. Il dst
punto può avanzare di una quantità diversa rispetto al src
puntatore, ma una volta tornato a un src
puntatore allineato , eseguiremo comunque solo negozi vettoriali non allineati dst
.
Per il testo UTF-8, ma principalmente costituito dal sottoinsieme ASCII di UTF-8, questo può essere buono: prestazioni elevate nel caso comune con comportamento corretto in tutti i casi. Quando c'è un sacco di non-ASCII, probabilmente sarà comunque peggio che rimanere sempre nel loop consapevole scalare UTF-8.
Rendere l'inglese più veloce a spese di altre lingue non è una decisione a prova di futuro se il rovescio della medaglia è significativo.
Nella locale turca ( tr_TR
), il risultato corretto da toupper('i')
è 'İ'
(U0130), non 'I'
(semplice ASCII). Vedi i commenti di Martin Bonner su una domanda tolower()
sull'essere lento su Windows.
Possiamo anche verificare un elenco di eccezioni e il fallback su scalare lì, come per i caratteri di input UTF8 multi-byte.
Con questa complessità, SSE4.2 PCMPISTRM
o qualcosa del genere potrebbe essere in grado di eseguire molti dei nostri controlli in una volta sola.
Hai caratteri ASCII o internazionali nelle stringhe?
Se si tratta dell'ultimo caso, "maiuscole" non è così semplice e dipende dall'alfabeto utilizzato. Ci sono alfabeti bicamerali e unicamerali. Solo gli alfabeti bicamerali hanno caratteri diversi per le lettere maiuscole e minuscole. Inoltre, ci sono caratteri compositi, come la lettera maiuscola latina 'DZ' (\ u01F1 'DZ') che usano il cosiddetto caso del titolo . Ciò significa che viene modificato solo il primo carattere (D).
Ti suggerisco di esaminare l' ICU e la differenza tra mappature di casi semplici e complete. Questo potrebbe aiutare:
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;
}
**
dopo i parametri sulla prima soluzione?
**
sia rimasto un errore di battitura nel tentativo di usare il carattere grassetto nella sintassi del codice.
toupper
viene chiamato con numeri negativi.
Quanto segue funziona per me.
#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
viene chiamato con numeri negativi.
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);
Quello più veloce se usi solo caratteri ASCII :
for(i=0;str[i]!=0;i++)
if(str[i]<='z' && str[i]>='a')
str[i]-=32;
Si noti che questo codice viene eseguito più velocemente ma funziona solo su ASCII e non è una soluzione "astratta".
Se hai bisogno di soluzioni UNICODE o di soluzioni più convenzionali e astratte, cerca altre risposte e lavora con i metodi delle stringhe C ++.
C++
, ma hai scritto una C
risposta qui. (Non sono uno dei downvoter.)
'
?
Finché stai bene solo con ASCII e puoi fornire un puntatore valido alla memoria RW, c'è un one-liner semplice e molto efficace in C:
void strtoupper(char* str)
{
while (*str) *(str++) = toupper((unsigned char)*str);
}
Ciò è particolarmente utile per stringhe semplici come identificatori ASCII che si desidera normalizzare nello stesso caso di caratteri. È quindi possibile utilizzare il buffer per costruire un'istanza 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 ...
. Inoltre, non c'è alcun buon motivo per renderlo così difficile da leggere. Questo prima copia anche la stringa e poi ci passa sopra. @La risposta di Luke è migliore in qualche modo, tranne che per non sfruttare le 'a'
costanti di carattere.
#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());
Questo funzionerà meglio di tutte le risposte che usano la funzione toupper globale, ed è presumibilmente ciò che sta facendo boost :: to_upper.
Questo perché :: toupper deve cercare la locale - perché potrebbe essere stata cambiata da un thread diverso - per ogni invocazione, mentre qui solo la chiamata a locale () ha questa penalità. E cercare le impostazioni locali in genere comporta il blocco.
Questo funziona anche con C ++ 98 dopo aver sostituito l'auto, l'uso del nuovo str.data () non costante e l'aggiunta di uno spazio per interrompere la chiusura del modello (">>" in ">>") in questo modo:
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
e back_inserter
(facendo in modo che la stringa venga copiata una sola volta). 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
viene chiamato con numeri negativi.
prova la toupper()
funzione ( #include <ctype.h>
). accetta caratteri come argomenti, le stringhe sono costituite da caratteri, quindi dovrai iterare su ogni singolo carattere che quando messo insieme comprende la stringa
toupper
viene chiamato con numeri negativi. Avresti dovuto menzionare il cast necessario unsigned char
.
Ecco l'ultimo codice con C ++ 11
std::string cmd = "Hello World";
for_each(cmd.begin(), cmd.end(), [](char& in){ in = ::toupper(in); });
toupper
viene chiamato con numeri negativi.
La risposta di @dirkgently è molto stimolante, ma voglio sottolineare che a causa della preoccupazione come mostrato di seguito,
Come tutte le altre funzioni di, il comportamento di std :: toupper non è definito se il valore dell'argomento non è né rappresentabile come carattere senza segno né uguale a EOF. Per utilizzare queste funzioni in modo sicuro con caratteri semplici (o caratteri firmati), l'argomento deve essere prima convertito in caratteri non firmati
Riferimento : std :: toupper
l'uso corretto di std::toupper
dovrebbe essere:
#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;
}
Produzione:
Hello world!
HELLO WORLD!
non sono sicuro che ci sia una funzione integrata. Prova questo:
Includere le librerie ctype.h OR cctype e stdlib.h come parte delle direttive del preprocessore.
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
viene chiamato con numeri negativi.
La mia soluzione (cancellando il sesto bit per l'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
viene chiamato con numeri negativi.
TUTTE queste soluzioni in questa pagina sono più difficili di quanto debbano essere.
Fai questo
RegName = "SomE StRing That you wAnt ConvErTed";
NameLength = RegName.Size();
for (int forLoop = 0; forLoop < NameLength; ++forLoop)
{
RegName[forLoop] = tolower(RegName[forLoop]);
}
RegName
è tuo string
. Ottieni le dimensioni della tua stringa non utilizzare string.size()
come tester reale, molto disordinato e può causare problemi. poi. il for
ciclo più elementare .
ricorda che la dimensione della stringa restituisce anche il delimitatore, quindi usa <e non <= nel tuo loop test.
l'output sarà: una stringa che vuoi convertire
tolower
loop e la maggior parte utilizza nomi di variabili di loop standard come i
, non i strani forLoop
.
Senza utilizzare alcuna libreria:
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;
}
Se ti occupi solo di caratteri a 8 bit (che assumono anche tutte le altre risposte tranne Milan Babuškov) puoi ottenere la velocità più veloce generando una tabella di ricerca al momento della compilazione usando la metaprogrammazione. Su ideone.com funziona 7 volte più veloce della funzione libreria e 3 volte più veloce di una versione scritta a mano ( http://ideone.com/sb1Rup ). È anche personalizzabile attraverso tratti senza rallentamento.
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 d'uso:
std::transform(in.begin(),in.end(),out.begin(),tableToUpper);
Per una descrizione approfondita (molte pagine) di come funziona mi permetto di collegare spudoratamente il mio 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;
}
Questa funzione c ++ restituisce sempre la stringa maiuscola ...
#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;
}
Uso questa soluzione. So che non dovresti modificare quell'area dati ... ma penso che sia principalmente per i bug di sovraccarico del buffer e il carattere null ... le cose del case superiore non sono le stesse.
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
- quale area dati non dovresti modificare?
str[i] = toupper(str[i]);
perfettamente bene (beh, non perfettamente bene, ma risolve la maggior parte delle cose sbagliate).
::toupper
molto probabilmente assume l'ASCII.