Como alguém poderia converter uma string para maiúscula? Os exemplos que encontrei no Google apenas têm que lidar com caracteres.
Como alguém poderia converter uma string para maiúscula? Os exemplos que encontrei no Google apenas têm que lidar com caracteres.
Respostas:
Algoritmos de cadeia de impulso:
#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()
pode ser implementado como uma macro. Isso pode causar um problema.
toupper
. Alguma ideia?
Solução curta usando C ++ 11 e toupper ().
for (auto & c: str) c = toupper(c);
c
seria do const char
tipo (de auto
)? Nesse caso, você não pode atribuí-lo (por causa da const
parte) ao que é retornado toupper(c)
.
c
precisa unsigned char
ser usado para que isso seja corrigido.
struct convert {
void operator()(char& c) { c = toupper((unsigned char)c); }
};
// ...
string uc_str;
for_each(uc_str.begin(), uc_str.end(), convert());
Nota: Alguns problemas com a solução superior:
21.5 Utilitários de sequência terminada por nulo
O conteúdo desses cabeçalhos deve ser o mesmo que os cabeçalhos da Biblioteca C Padrão <ctype.h>, <wctype.h>, <string.h>, <wchar.h> e <stdlib.h> [...]
O que significa que os cctype
membros podem muito bem ser macros não adequadas para consumo direto em algoritmos padrão.
Outro problema com o mesmo exemplo é que ele não lança o argumento ou verifica se isso não é negativo; isso é especialmente perigoso para sistemas em que a planície char
é assinada. (A razão é: se isso for implementado como uma macro, provavelmente usará uma tabela de pesquisa e seus argumentos serão indexados nessa tabela. Um índice negativo fornecerá UB.)
Esse problema é vetorizável com SIMD para o conjunto de caracteres ASCII.
Teste preliminar com x86-64 gcc 5.2 -O3 -march=native
em um Core2Duo (Merom). A mesma sequência de 120 caracteres (ASCII misturada em minúsculas e não minúsculas), convertida em um loop 40M vezes (sem inlining de arquivos cruzados, para que o compilador não possa otimizar ou retirar nada disso do loop). Os mesmos buffers de origem e de destino, portanto, sem sobrecarga de malloc ou efeitos de memória / cache: os dados ficam quentes no cache L1 o tempo todo e somos puramente vinculados à CPU.
boost::to_upper_copy<char*, std::string>()
: 198.0s . Sim, o Boost 1.58 no Ubuntu 15.10 é realmente muito lento. Eu criei um perfil e dei um único passo no asm em um depurador, e é muito, muito ruim: há um broadcast_ dinâmico de uma variável de localidade acontecendo por caractere !!! (dynamic_cast recebe várias chamadas para strcmp). Isso acontece com LANG=C
e comLANG=en_CA.UTF-8
.
Eu não testei usando um RangeT diferente de std :: string. Talvez a outra forma deto_upper_copy
otimiza melhor, mas eu acho que vai sempre new
/ malloc
espaço para a cópia, por isso é mais difícil de teste. Talvez algo que eu fiz seja diferente de um caso de uso normal, e talvez o g ++ normalmente interrompido possa elevar o material de configuração do código de idioma do loop por caractere. Meu loop lendo de std::string
e escrevendo para a char dstbuf[4096]
faz sentido para o teste.
loop chamando glibc toupper
: 6.67s ( embora não verifique o int
resultado para um potencial UTF-8 de vários bytes. Isso importa para o turco.)
cmov
, com a tabela quente em L1 de qualquer maneira.Veja também esta pergunta sobretoupper()
ser lento no Windows quando um código de idioma estiver definido .
Fiquei chocado que Boost é uma ordem de magnitude mais lenta que as outras opções. Verifiquei duas vezes se havia -O3
ativado e até dei um passo para ver o que estava fazendo. É quase exatamente a mesma velocidade com o clang ++ 3.8. Possui uma sobrecarga enorme dentro do loop por caractere. O resultado perf record
/ report
(para o 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 apenas auto-vectorizam loops quando a contagem de iterações é conhecida antes do loop. (ou seja, os loops de pesquisa, como a implementação em C simples strlen
, não se autovectorizam.)
Portanto, para strings pequenas o suficiente para caber no cache, obtemos uma aceleração significativa para strings com ~ 128 caracteres desde o strlen
início. Isso não será necessário para cadeias de comprimento explícito (como 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;
}
Qualquer libc decente terá uma eficiência strlen
que é muito mais rápido do que repetir um byte de cada vez; portanto, loops vetorizados de strlen e toupper separados são mais rápidos.
Linha de base: um loop que verifica um 0 de terminação em tempo real.
Tempos para iterações de 40M, em um Core2 (Merom) 2.4GHz. gcc 5.2 -O3 -march=native
. (Ubuntu 15.10). dst != src
(por isso fazemos uma cópia), mas eles não se sobrepõem (e não estão por perto). Ambos estão alinhados.
Alguns resultados são um pouco diferentes com o clang.
O loop de marca de microbench que chama a função está em um arquivo separado. Caso contrário, ele alinha estrlen()
é içado para fora do loop, e corre drasticamente mais rápido, esp. para 16 strings de caracteres (0,187s).
Isso tem a grande vantagem de que o gcc pode auto-vetorizá-lo para qualquer arquitetura, mas a grande desvantagem de ser mais lento no caso geralmente comum de pequenas seqüências de caracteres.
Portanto, existem grandes acelerações, mas a vetorização automática do compilador não produz um ótimo código, esp. para limpeza dos últimos até 15 caracteres.
Baseado na minha função flip-case que inverte o caso de todos os caracteres alfabéticos. Ele tira proveito do "truque de comparação não assinado", onde você pode fazer low < a && a <= high
uma única comparação não assinada por mudança de intervalo, para que qualquer valor menor que seja low
agrupado em um valor maior que high
. (Isso funciona se low
e high
não estiver muito distante.)
O SSE possui apenas uma comparação maior assinada, mas ainda podemos usar o truque "comparação não assinada" deslocando o intervalo para o final do intervalo assinado: Subtraia 'a' + 128, para que os caracteres alfabéticos variem de -128 a -128 +25 (-128 + 'z' - 'a')
Observe que adicionar 128 e subtrair 128 são a mesma coisa para números inteiros de 8 bits. Não há nenhum lugar para o transporte ir, por isso é apenas xor (add carryless), invertendo a parte mais alta.
#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
}
Dada essa função que funciona para um vetor, podemos chamá-la em um loop para processar uma string inteira. Como já estamos segmentando o SSE2, podemos fazer uma verificação de fim de cadeia vetorizada ao mesmo tempo.
Também podemos fazer muito melhor para a "limpeza" dos últimos até 15 bytes restantes após a execução de vetores de 16B: a caixa superior é idempotente, portanto, reprocessar alguns bytes de entrada é bom. Fazemos uma carga desalinhada dos últimos 16B da fonte e a armazenamos no buffer de destino sobrepondo a última loja 16B do loop.
O único momento em que isso não funciona é quando toda a cadeia está abaixo de 16B: Mesmo quando dst=src
a leitura-modificação-gravação não atômica não é a mesma coisa que não tocar em alguns bytes e pode quebrar o código multithread.
Temos um loop escalar para isso e também para nos src
alinharmos. Como não sabemos onde estará o 0 final, uma carga desalinhada poderá passar src
para a próxima página e ocorrer um defeito. Se precisarmos de bytes em um pedaço 16B alinhado, é sempre seguro carregar todo o pedaço 16B alinhado.
Fonte completa: em uma essência do github .
// 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;
}
Tempos para iterações de 40M, em um Core2 (Merom) 2.4GHz. gcc 5.2 -O3 -march=native
. (Ubuntu 15.10). dst != src
(por isso fazemos uma cópia), mas eles não se sobrepõem (e não estão por perto). Ambos estão alinhados.
(Na verdade, com o tempo programado _mm_store
no loop, não _mm_storeu
, porque o storeu é mais lento no Merom, mesmo quando o endereço está alinhado. É bom no Nehalem e mais tarde. Eu também deixei o código como está por enquanto, em vez de corrigir a falha de cópia o 0 final em alguns casos, porque não quero cronometrar tudo.)
Portanto, para cadeias curtas maiores que 16B, isso é drasticamente mais rápido que vetorizado automaticamente. Comprimentos com largura inferior a um vetor não representam um problema. Eles podem ser um problema ao operar no local, devido a um estol de encaminhamento de loja. (Mas observe que ainda é bom processar nossa própria saída, em vez da entrada original, porque o toupper é idempotente).
Há muito espaço para ajustar isso para diferentes casos de uso, dependendo do que o código circundante deseja e da microarquitetura de destino. Conseguir que o compilador emita um código legal para a parte da limpeza é complicado. Usar ffs(3)
(que compila para bsf ou tzcnt no x86) parece bom, mas obviamente esse bit precisa ser repensado, pois notei um bug depois de escrever a maior parte dessa resposta (consulte os comentários do FIXME).
Acelerações de vetor para seqüências ainda menores podem ser obtidas com movq
ou movd
cargas / armazenamentos. Personalize conforme necessário para o seu caso de uso.
Podemos detectar quando nosso vetor possui bytes com o conjunto de bits alto e, nesse caso, retornar a um loop escalar com reconhecimento utf-8 para esse vetor. O dst
ponto pode avançar em uma quantidade diferente do src
ponteiro, mas quando voltarmos a um src
ponteiro alinhado , ainda faremos armazenamentos de vetor desalinhados dst
.
Para texto que é UTF-8, mas consiste principalmente do subconjunto ASCII de UTF-8, isso pode ser bom: alto desempenho no caso comum, com comportamento correto em todos os casos. Porém, quando há muito não ASCII, provavelmente será pior do que permanecer no loop ciente UTF-8 escalar o tempo todo.
Tornar o inglês mais rápido às custas de outros idiomas não é uma decisão preparada para o futuro se a desvantagem for significativa.
No código do idioma turco ( tr_TR
), o resultado correto toupper('i')
é 'İ'
(U0130), não 'I'
(ASCII simples). Veja os comentários de Martin Bonner sobre uma pergunta sobre tolower()
ser lento no Windows.
Também podemos verificar se há uma lista de exceções e um fallback para escalar, como caracteres de entrada UTF8 de vários bytes.
Com essa complexidade, o SSE4.2 PCMPISTRM
ou algo assim pode ser capaz de realizar muitas de nossas verificações de uma só vez.
Você tem caracteres ASCII ou internacionais em strings?
Se for o último caso, "maiúsculas" não é tão simples e depende do alfabeto usado. Existem alfabetos bicameral e unicameral. Somente alfabetos bicameral têm caracteres diferentes para maiúsculas e minúsculas. Além disso, existem caracteres compostos, como a letra maiúscula em latim 'DZ' (\ u01F1 'DZ') que usam a chamada maiúscula . Isso significa que apenas o primeiro caractere (D) é alterado.
Eu sugiro que você analise a UTI e a diferença entre mapeamentos de casos simples e completos. Isso pode ajudar:
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;
}
**
após os parâmetros na primeira solução fazem?
**
é um erro de digitação que resta de tentar usar fonte em negrito na sintaxe do código.
toupper
é chamado com números negativos.
O seguinte funciona para mim.
#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
é chamado com números negativos.
Use uma 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);
O mais rápido se você usar apenas caracteres ASCII :
for(i=0;str[i]!=0;i++)
if(str[i]<='z' && str[i]>='a')
str[i]-=32;
Observe que esse código é executado mais rapidamente, mas funciona apenas em ASCII e não é uma solução "abstrata".
Se você precisar de soluções UNICODE ou soluções mais convencionais e abstratas, procure outras respostas e trabalhe com métodos de seqüências de caracteres C ++.
C++
, mas você escreveu uma C
resposta aqui. (Eu não sou um dos downvoters.)
'
?
Desde que você esteja bem com apenas ASCII e possa fornecer um ponteiro válido para a memória RW, existe um one-liner simples e muito eficaz em C:
void strtoupper(char* str)
{
while (*str) *(str++) = toupper((unsigned char)*str);
}
Isso é especialmente bom para cadeias simples, como identificadores ASCII, que você deseja normalizar no mesmo caso de caractere. Você pode usar o buffer para construir uma instância 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 ...
. Também não há boas razões para dificultar a leitura. Isso também copia a string primeiro e depois passa sobre ela. @ A resposta de Luke é melhor em alguns aspectos, exceto por não tirar vantagem das 'a'
constantes de caracteres.
#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());
Isso terá um desempenho melhor do que todas as respostas que usam a função global toupper e é presumivelmente o que boost :: to_upper está fazendo por baixo.
Isso ocorre porque :: toupper precisa procurar a localidade - porque pode ter sido alterada por um encadeamento diferente - para cada chamada, enquanto aqui apenas a chamada para locale () tem essa penalidade. E procurar o código do idioma geralmente envolve trancar o cadeado.
Isso também funciona com o C ++ 98 após a substituição automática, o uso do novo non-const str.data () e a adição de um espaço para interromper o fechamento do modelo (">>" para ">>") assim:
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
(fazendo com que a sequência seja copiada apenas uma vez). 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
é chamado com números negativos.
tente o toupper()
função ( #include <ctype.h>
). aceita caracteres como argumentos, as strings são compostas de caracteres, portanto, você terá que iterar sobre cada caractere individual que, quando reunidos, compreende a string
toupper
é chamada com números negativos. Você deveria ter mencionado o elenco necessário unsigned char
.
Aqui está o código mais recente com o C ++ 11
std::string cmd = "Hello World";
for_each(cmd.begin(), cmd.end(), [](char& in){ in = ::toupper(in); });
toupper
é chamado com números negativos.
A resposta de @dirkgently é muito inspiradora, mas quero enfatizar que, devido à preocupação mostrada abaixo,
Como todas as outras funções de, o comportamento de std :: toupper é indefinido se o valor do argumento não for representável como char não assinado nem igual a EOF. Para usar essas funções com segurança com caracteres simples (ou caracteres assinados), o argumento deve primeiro ser convertido em caracteres não assinados.
Referência : std :: toupper
o uso correto de std::toupper
deve ser:
#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;
}
Resultado:
Hello world!
HELLO WORLD!
não tenho certeza se existe uma função incorporada. Tente o seguinte:
Inclua as bibliotecas ctype.h OR cctype, bem como o stdlib.h como parte das diretivas do pré-processador.
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
é chamado com números negativos.
Minha solução (limpando o sexto bit para 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
é chamado com números negativos.
Todas essas soluções nesta página são mais difíceis do que precisam.
Faça isso
RegName = "SomE StRing That you wAnt ConvErTed";
NameLength = RegName.Size();
for (int forLoop = 0; forLoop < NameLength; ++forLoop)
{
RegName[forLoop] = tolower(RegName[forLoop]);
}
RegName
é seu string
. Obtenha seu tamanho de string, não use string.size()
como seu testador real, muito confuso e pode causar problemas. então. o for
loop mais básico .
Lembre-se de que o tamanho da string também retorna o delimitador, portanto, use <e não <= no seu teste de loop.
a saída será: alguma string que você deseja converter
tolower
loops simples , e a maioria deles usa nomes de variáveis de loop padrão i
, como não estranhos forLoop
.
Sem usar nenhuma biblioteca:
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 você estiver preocupado apenas com caracteres de 8 bits (que todas as outras respostas, exceto Milan Babuškov também assumem), poderá obter a velocidade mais rápida gerando uma tabela de consulta em tempo de compilação usando metaprogramação. No ideone.com, isso é executado 7 vezes mais rápido que a função de biblioteca e 3x mais rápido que uma versão escrita à mão ( http://ideone.com/sb1Rup ). Também é personalizável através de características sem desaceleração.
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);
}
com caso de uso:
std::transform(in.begin(),in.end(),out.begin(),tableToUpper);
Para uma descrição detalhada (em várias páginas) de como ele funciona, permita-me conectar descaradamente o meu 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;
}
Essa função c ++ sempre retorna a cadeia de caracteres em maiúsculas ...
#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;
}
Eu uso essa solução. Eu sei que você não deve modificar essa área de dados .... mas acho que isso é principalmente para erros de saturação de buffer e caracteres nulos ... as coisas de maiúsculas e minúsculas não são a mesma coisa.
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
- qual área de dados você não deve modificar?
str[i] = toupper(str[i]);
perfeitamente fina (bem, não perfeitamente fina, mas corrige a maioria das coisas erradas).
::toupper
provavelmente assume ASCII.