Como converter std :: string para minúsculas?

777

Quero converter um std::stringpara minúsculo. Estou ciente da função tolower(), no entanto, no passado, tive problemas com essa função e ela dificilmente é ideal, pois o uso com a std::stringexigiria a iteração sobre cada caractere.

Existe uma alternativa que funcione 100% do tempo?

Konrad
fonte
34
De que outra forma você converteria cada elemento de uma lista de qualquer coisa para outra, sem percorrer a lista? Uma string é apenas uma lista de caracteres; se você precisar aplicar alguma função a cada caractere, precisará repetir a string. Não há maneira de contornar isso.
14
Por que exatamente essa pergunta reduz a classificação? Eu não tenho um problema com a iteração através da minha corda, mas estou perguntando se existem outras funções para além de tolower (), toupper () etc.
Konrad
3
Se você possui uma matriz de caracteres do estilo C, acho que você poderá adicionar ox20202020 a cada bloco de 4 caracteres (desde que todos já estejam em maiúsculas) para converter 4 caracteres em minúsculas por vez.
13
@ Dan: Se eles já podem estar em minúsculas, mas definitivamente são AZ ou az, você pode OU com 0x20 em vez de adicionar. Uma daquelas otimizações tão inteligentes que provavelmente são idiotas que quase nunca valem a pena ...
Steve Jessop
4
Não sei por que teria sido negado o voto ... certamente está redigido um pouco estranhamente (porque você precisa percorrer todos os itens de alguma forma), mas é uma pergunta válida
warren

Respostas:

905

Adaptado de perguntas não tão frequentes :

#include <algorithm>
#include <cctype>
#include <string>

std::string data = "Abc";
std::transform(data.begin(), data.end(), data.begin(),
    [](unsigned char c){ return std::tolower(c); });

Você realmente não vai se safar sem percorrer cada personagem. Não há como saber se o personagem é minúsculo ou maiúsculo.

Se você realmente odeia tolower(), aqui está uma alternativa especializada apenas em ASCII que eu não recomendo que você use:

char asciitolower(char in) {
    if (in <= 'Z' && in >= 'A')
        return in - ('Z' - 'z');
    return in;
}

std::transform(data.begin(), data.end(), data.begin(), asciitolower);

Esteja ciente de que tolower()só é possível fazer uma substituição por caractere de byte único, o que é inadequado para muitos scripts, especialmente se você estiver usando uma codificação de bytes múltiplos como UTF-8.

Stefan Mai
fonte
25
(Pode ser que os algoritmos em questão tenham mudado pouco) @Stefan Mai: Que tipo de "sobrecarga" existe ao chamar algoritmos STL? As funções são bastante simples (ou seja, simples para loops) e geralmente são incorporadas, pois você raramente tem muitas chamadas para a mesma função com os mesmos parâmetros de modelo na mesma unidade de compilação.
EQ-
257
Toda vez que você assume que os personagens são ASCII, Deus mata um gatinho. :(
Brian Gordon
13
Seu primeiro exemplo tem um comportamento indefinido (passando charpara ::tolower(int).) Você precisa garantir que não passa um valor negativo.
Juanchopanza
37
-1 esse uso ::tolowerpode travar, é UB para entrada não ASCII.
Saúde e hth. - Alf
7
O :: é necessário antes de ativar para indicar que está no espaço de nomes mais externo. Se você usar esse código em outro espaço para nome, pode haver uma definição diferente (possivelmente não relacionada) de tolower que acabaria sendo selecionada preferencialmente sem o ::.
Charles Ofria
320

O Boost fornece um algoritmo de string para isso :

#include <boost/algorithm/string.hpp>

std::string str = "HELLO, WORLD!";
boost::algorithm::to_lower(str); // modifies str

Ou, para não local :

#include <boost/algorithm/string.hpp>

const std::string str = "HELLO, WORLD!";
const std::string lower_str = boost::algorithm::to_lower_copy(str);
Roubar
fonte
2
Suponho que isso não tenha os mesmos problemas que o tolower com entrada ASCII?
paulm
19
Falha no não-ASCII-7.
DevSolar 27/02
1
Existe uma versão não no local disso?
Ray
5
@Ray, sim,to_lower_copy
smac89
234

tl; dr

Use a biblioteca da UTI . Caso contrário, sua rotina de conversão será interrompida silenciosamente nos casos que você provavelmente nem conhece.


Primeiro você tem que responder a uma pergunta: Qual é a codificação do seu std::string? É ISO-8859-1? Ou talvez ISO-8859-8? Ou página de código 1252 do Windows? O que você está usando para converter maiúsculas para minúsculas sabe disso? (Ou falha miseravelmente para os personagens terminados 0x7f?)

Se você estiver usando UTF-8 (a única opção sensata entre as codificações de 8 bits) std::stringcomo contêiner, já estará enganando-se a acreditar que ainda está no controle das coisas, porque está armazenando uma sequência de caracteres multibyte em um contêiner que não conhece o conceito multibyte. Mesmo algo tão simples quanto .substr()uma bomba-relógio. (Como a divisão de uma sequência multibyte resultará em uma (sub)) string inválida.)

E assim que você tenta algo como std::toupper( 'ß' ), em qualquer codificação, está com problemas profundos. (Como simplesmente não é possível fazer isso "corretamente" com a biblioteca padrão, que pode fornecer apenas um caractere de resultado, não o "SS"necessário aqui.) [1] Outro exemplo seria std::tolower( 'I' ): o que deve gerar resultados diferentes, dependendo da localidade . Na Alemanha, 'i'estaria correto; na Turquia, 'ı'(LETRA LATINA PEQUENA I) é o resultado esperado (que, novamente, é mais de um byte na codificação UTF-8). Ainda outro exemplo é o sigma grego , maiúsculo '∑'e minúsculo 'σ'... exceto no final de uma palavra, onde está 'ς'.

Portanto, qualquer conversão de caso que funcione em um caractere de cada vez, ou pior, em um byte de cada vez, é interrompida pelo design.

Depois, há o ponto de que a biblioteca padrão, para o que é capaz de fazer, depende de quais localidades são suportadas na máquina em que seu software está executando ... e o que você faz se não estiver?

Então, o que você realmente está procurando é uma classe de string capaz de lidar com tudo isso corretamente, e essa não é nenhuma das std::basic_string<>variantes .

(Nota do C ++ 11: std::u16stringe std::u32stringsão melhores , mas ainda não são perfeitas. O C ++ 20 trouxe std::u8string, mas tudo o que faz é especificar a codificação. Em muitos outros aspectos, eles ainda permanecem ignorantes da mecânica do Unicode, como normalização, agrupamento, etc. .)

Enquanto o Boost parece bom, em termos de API, o Boost.Locale é basicamente um invólucro em torno da ICU . Se o Boost for compilado com suporte à ICU ... se não for, o Boost.Locale será limitado ao suporte de localidade compilado para a biblioteca padrão.

E acredite em mim, fazer com que o Boost compile com a UTI pode ser uma dor real às vezes. (Como não existem binários pré-compilados para o Windows, você precisará fornecê-los juntamente com o aplicativo e isso abre uma nova lata de worms ...)

Então, pessoalmente, eu recomendaria obter suporte completo a Unicode diretamente da boca do cavalo e usar a biblioteca da ICU diretamente:

#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <unicode/locid.h>

#include <iostream>

int main()
{
    /*                          "Odysseus" */
    char const * someString = u8"ΟΔΥΣΣΕΥΣ";
    icu::UnicodeString someUString( someString, "UTF-8" );
    // Setting the locale explicitly here for completeness.
    // Usually you would use the user-specified system locale,
    // which *does* make a difference (see ı vs. i above).
    std::cout << someUString.toLower( "el_GR" ) << "\n";
    std::cout << someUString.toUpper( "el_GR" ) << "\n";
    return 0;
}

Compile (com G ++ neste exemplo):

g++ -Wall example.cpp -licuuc -licuio

Isto dá:

ὀδυσσεύς

Observe que a conversão Σ <-> σ no meio da palavra e a conversão Σ <-> ς no final da palavra. Uma <algorithm>solução não baseada pode lhe dar isso.


[1] Em 2017, o Conselho de Ortografia Alemã determinou que "ẞ" U + 1E9E LETRA DE CAPITAL LATINA SHARP S poderia ser usada oficialmente, como uma opção ao lado da conversão tradicional de "SS" para evitar ambiguidade, por exemplo, em passaportes (onde os nomes são maiúsculos ) Meu lindo exemplo, tornado obsoleto por decisão do comitê ...

DevSolar
fonte
19
Esta é a resposta correta no caso geral. O padrão não fornece nada para lidar com nada, exceto "ASCII", exceto mentiras e enganos. Isso faz você pensar que talvez possa lidar com talvez UTF-16, mas não pode. Como esta resposta diz, você não pode obter o comprimento de caractere adequado (não o comprimento de bytes) de uma string UTF-16 sem fazer seu próprio manuseio unicode. Se você precisar lidar com texto real, use a UTI. Obrigado, @DevSolar
Expiação limitada
O ICU está disponível por padrão no Ubuntu / Windows ou precisa ser instalado separadamente? Também que tal esta resposta: stackoverflow.com/a/35075839/207661 ?
Shital Shah
1
Ei, olha, uma resposta real! Obrigado por me apontar no DevSolar direto certo.
22416 Dan Bechard
2
@DevSolar Concordou! O conceito de comprimento não tem sentido no texto (poderíamos adicionar ligaduras à lista de infratores). Dito isto, como as pessoas estão acostumadas a tabular e controlar caracteres ocupando uma unidade de comprimento, os pontos de código seriam a medida mais intuitiva. Oh, e obrigado por dar a resposta correta, é triste vê-lo tão longe :-(
masaers
3
@LF Marginalmente melhor. Mas muitas coisas ainda não estão cobertas: touppere tolowerainda funcionam em caracteres únicos. A classe de string ainda não tem noção de normalização (por exemplo, se um "ü" é codificado como "u com diaeresis" ou "u + diaeresis combinada") ou onde uma string pode ou não ser separada. A lista continua. u8string é (como as outras classes de string padrão) apropriadas para "passagem". Mas se você deseja processar Unicode, precisa de uma UTI.
DevSolar 06/07/19
36

Usando o loop for baseado em intervalo do C ++ 11, um código mais simples seria:

#include <iostream>       // std::cout
#include <string>         // std::string
#include <locale>         // std::locale, std::tolower

int main ()
{
  std::locale loc;
  std::string str="Test String.\n";

 for(auto elem : str)
    std::cout << std::tolower(elem,loc);
}
entalha
fonte
9
No entanto, em uma máquina francesa, este programa não converte caracteres não ASCII permitidos no idioma francês. Por exemplo, uma string 'Test String123. É Ï \ n 'será convertido para:' test string123. É although \ n ', embora os caracteres É Ï e suas letras minúsculas' é 'e' ï 'sejam permitidos em francês. Parece que nenhuma solução para isso foi fornecida por outras mensagens deste segmento.
incisa
Eu acho que você precisa definir um local apropriado para isso.
user1095108
@incises, alguém postou uma resposta sobre a UTI e esse certamente é o caminho a percorrer. Mais fácil do que a maioria das outras soluções que tentariam entender o código do idioma.
Alexis Wilke
Prefiro não usar bibliotecas externas quando possível, pessoalmente.
kayleeFrye_onDeck
15

Este é um acompanhamento da resposta de Stefan Mai: se você deseja colocar o resultado da conversão em outra string, é necessário pré-alocar seu espaço de armazenamento antes da chamada std::transform. Como o STL armazena caracteres transformados no iterador de destino (incrementando-o a cada iteração do loop), a sequência de destino não será redimensionada automaticamente e você corre o risco de perder memória.

#include <string>
#include <algorithm>
#include <iostream>

int main (int argc, char* argv[])
{
  std::string sourceString = "Abc";
  std::string destinationString;

  // Allocate the destination space
  destinationString.resize(sourceString.size());

  // Convert the source string to lower case
  // storing the result in destination string
  std::transform(sourceString.begin(),
                 sourceString.end(),
                 destinationString.begin(),
                 ::tolower);

  // Output the result of the conversion
  std::cout << sourceString
            << " -> "
            << destinationString
            << std::endl;
}
user2218467
fonte
1
Isso não foi redimensionado para mim
Purefan
Também pode usar um iterador de inserção traseira aqui em vez de redimensionar manualmente.
chili
11

Outra abordagem usando intervalo baseado em loop com variável de referência

string test = "Hello World";
for(auto& c : test)
{
   c = tolower(c);
}

cout<<test<<endl;
Gilson PJ
fonte
6

Até onde eu vejo, as bibliotecas Boost são realmente ruins em termos de desempenho. Testei o unordered_map para STL e a média foi três vezes mais lenta (o melhor caso 2, o pior foi 10 vezes). Além disso, esse algoritmo parece muito baixo.

A diferença é tão grande que tenho certeza de que qualquer acréscimo que você precise fazer tolowerpara torná-lo igual ao impulso "para suas necessidades" será muito mais rápido que o impulso.

Fiz esses testes em um Amazon EC2; portanto, o desempenho variou durante o teste, mas você ainda entende.

./test
Elapsed time: 12365milliseconds
Elapsed time: 1640milliseconds
./test
Elapsed time: 26978milliseconds
Elapsed time: 1646milliseconds
./test
Elapsed time: 6957milliseconds
Elapsed time: 1634milliseconds
./test
Elapsed time: 23177milliseconds
Elapsed time: 2421milliseconds
./test
Elapsed time: 17342milliseconds
Elapsed time: 14132milliseconds
./test
Elapsed time: 7355milliseconds
Elapsed time: 1645milliseconds

-O2 fez assim:

./test
Elapsed time: 3769milliseconds
Elapsed time: 565milliseconds
./test
Elapsed time: 3815milliseconds
Elapsed time: 565milliseconds
./test
Elapsed time: 3643milliseconds
Elapsed time: 566milliseconds
./test
Elapsed time: 22018milliseconds
Elapsed time: 566milliseconds
./test
Elapsed time: 3845milliseconds
Elapsed time: 569milliseconds

Fonte:

string str;
bench.start();
for(long long i=0;i<1000000;i++)
{
    str="DSFZKMdskfdsjfsdfJDASFNSDJFXCKVdnjsafnjsdfjdnjasnJDNASFDJDSFSDNJjdsanjfsdnfjJNFSDJFSD";
    boost::algorithm::to_lower(str);
}
bench.end();

bench.start();
for(long long i=0;i<1000000;i++)
{
    str="DSFZKMdskfdsjfsdfJDASFNSDJFXCKVdnjsafnjsdfjdnjasnJDNASFDJDSFSDNJjdsanjfsdnfjJNFSDJFSD";
    for(unsigned short loop=0;loop < str.size();loop++)
    {
        str[loop]=tolower(str[loop]);
    }
}
bench.end();

Acho que devo fazer os testes em uma máquina dedicada, mas usarei este EC2 para que eu realmente não precise testá-lo na minha máquina.

Etherealone
fonte
1
Você abriu as opções de otimização ao compilá-lo? Eu estou pensando que a biblioteca de impulso pesado STL deve funcionar melhor com alto nível de otimização.
Wei Song
1
Eu usei -O2 em um dos testes e nada mais.
Etherealone
2
O desempenho do unordered_map depende do algoritmo de hash combinado com os dados que você está usando. Não existe um algoritmo de hash mágico que funcione para todos e quaisquer dados para tornar o unordered_map o mais rápido possível. Compare e experimente coisas diferentes. A razão pela qual você está obtendo desempenho pior é porque, com o hash que você está usando, você recebe muitas colisões, o que basicamente causa uma pesquisa em uma lista. Confira este site para obter mais informações: fgda.pl/post/7/gcc-hash-map-vs-unordered-map Para meus propósitos, a função fornecida no link reduziu colisões e, portanto, foi muito rápida.
LeetNightshade 18/09/12
6

A maneira mais simples de converter string em loweercase sem se preocupar com o namespace std é a seguinte

1: string com / sem espaços

#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main(){
    string str;
    getline(cin,str);
//------------function to convert string into lowercase---------------
    transform(str.begin(), str.end(), str.begin(), ::tolower);
//--------------------------------------------------------------------
    cout<<str;
    return 0;
}

2: string sem espaços

#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main(){
    string str;
    cin>>str;
//------------function to convert string into lowercase---------------
    transform(str.begin(), str.end(), str.begin(), ::tolower);
//--------------------------------------------------------------------
    cout<<str;
    return 0;
}
Atul Rokade
fonte
5

std::ctype::tolower()da biblioteca de localização C ++ padrão fará isso corretamente para você. Aqui está um exemplo extraído da página de referência para baixar

#include <locale>
#include <iostream>

int main () {
  std::locale::global(std::locale("en_US.utf8"));
  std::wcout.imbue(std::locale());
  std::wcout << "In US English UTF-8 locale:\n";
  auto& f = std::use_facet<std::ctype<wchar_t>>(std::locale());
  std::wstring str = L"HELLo, wORLD!";
  std::wcout << "Lowercase form of the string '" << str << "' is ";
  f.tolower(&str[0], &str[0] + str.size());
  std::wcout << "'" << str << "'\n";
}
Sameer
fonte
Bom, contanto que você possa converter os caracteres no lugar. E se a sua string de origem for const? Isso parece torná-lo um pouco mais confuso (por exemplo, não parece que você possa usar f.tolower()), já que você precisa colocar os caracteres em uma nova string. Você usaria transform()e algo parecido std::bind1st( std::mem_fun() )com o operador?
Quazar
Para uma string const, podemos apenas fazer uma cópia local e depois convertê-la no lugar.
Sameer
Sim, porém, fazer uma cópia adiciona mais sobrecarga.
quazar 4/09/16
Você pode usar std :: transform com a versão do ctype :: tolower que não aceita ponteiros. Use um adaptador iterador de inserção traseira e você nem precisa se preocupar em pré-dimensionar sua string de saída.
chili
Ótimo, especialmente porque nos libstdc ++ 's tolowercom localeparâmetro, a chamada implícita para use_facetparece ser um gargalo de desempenho. Um dos meus colegas de trabalho alcançou um aumento de velocidade de vários 100% ao substituir boost::iequals(que tem esse problema) por uma versão em que use_faceté chamada apenas uma vez fora do loop.
Arne Vogel
3

Uma alternativa ao Boost é o POCO (pocoproject.org).

O POCO fornece duas variantes:

  1. A primeira variante faz uma cópia sem alterar a sequência original.
  2. A segunda variante altera a sequência original no lugar.
    As versões "no local" sempre têm "InPlace" no nome.

Ambas as versões são demonstradas abaixo:

#include "Poco/String.h"
using namespace Poco;

std::string hello("Stack Overflow!");

// Copies "STACK OVERFLOW!" into 'newString' without altering 'hello.'
std::string newString(toUpper(hello));

// Changes newString in-place to read "stack overflow!"
toLowerInPlace(newString);
Jason Enochs
fonte
3

Existe uma maneira de converter maiúsculas para minúsculas SEM fazer testes , e é bem direto. O uso da função isupper () / macro do clocale.h deve resolver os problemas relacionados à sua localização, mas, se não, você sempre pode ajustar o UtoL [] ao conteúdo do seu coração.

Dado que os caracteres de C são realmente apenas ints de 8 bits (ignorando os amplos conjuntos de caracteres no momento), você pode criar uma matriz de 256 bytes contendo um conjunto alternativo de caracteres e, na função de conversão, use os caracteres da sua string como subscritos no matriz de conversão.

Em vez de um mapeamento 1 por 1, forneça aos membros da matriz maiúscula os valores int BYTE para os caracteres minúsculos. Você pode achar islower () e isupper () útil aqui.

insira a descrição da imagem aqui

O código fica assim ...

#include <clocale>
static char UtoL[256];
// ----------------------------------------------------------------------------
void InitUtoLMap()  {
    for (int i = 0; i < sizeof(UtoL); i++)  {
        if (isupper(i)) {
            UtoL[i] = (char)(i + 32);
        }   else    {
            UtoL[i] = i;
        }
    }
}
// ----------------------------------------------------------------------------
char *LowerStr(char *szMyStr) {
    char *p = szMyStr;
    // do conversion in-place so as not to require a destination buffer
    while (*p) {        // szMyStr must be null-terminated
        *p = UtoL[*p];  
        p++;
    }
    return szMyStr;
}
// ----------------------------------------------------------------------------
int main() {
    time_t start;
    char *Lowered, Upper[128];
    InitUtoLMap();
    strcpy(Upper, "Every GOOD boy does FINE!");

    Lowered = LowerStr(Upper);
    return 0;
}

Essa abordagem permitirá, ao mesmo tempo, que você remapeie os outros caracteres que deseja alterar.

Essa abordagem tem uma enorme vantagem ao executar em processadores modernos, não há necessidade de fazer previsão de ramificação, pois não há testes que incluam ramificação. Isso economiza a lógica de previsão de ramificação da CPU para outros loops e tende a evitar paralisações no pipeline.

Alguns aqui podem reconhecer essa abordagem como a mesma usada para converter EBCDIC em ASCII.

user2548100
fonte
2
"Existe uma maneira de converter maiúsculas para minúsculas, SEM fazer testes", já ouviu falar em tabelas de pesquisa?
Gábor Buella
1
Comportamento indefinido para caracteres negativos.
Roland Illig
As CPUs modernas têm gargalo na memória e não na CPU. Benchmarking seria interessante.
Contango 14/04
3

Como nenhuma das respostas mencionou a próxima biblioteca Ranges, que está disponível na biblioteca padrão desde C ++ 20 e atualmente disponível separadamente no GitHub como range-v3, gostaria de adicionar uma maneira de executar essa conversão usando-a.

Para modificar a sequência no local:

str |= action::transform([](unsigned char c){ return std::tolower(c); });

Para gerar uma nova sequência:

auto new_string = original_string
    | view::transform([](unsigned char c){ return std::tolower(c); });

(Não esqueça #include <cctype>dos cabeçalhos de intervalos necessários.)

Nota: o uso de unsigned charcomo argumento para o lambda é inspirado na cppreference , que afirma:

Como todas as outras funções de <cctype>, o comportamento de std::toloweré indefinido se o valor do argumento não for representável unsigned charnem igual a EOF. Para usar essas funções com segurança com chars simples signed char, o argumento deve primeiro ser convertido em unsigned char:

char my_tolower(char ch)
{
    return static_cast<char>(std::tolower(static_cast<unsigned char>(ch)));
}

Da mesma forma, eles não devem ser usados ​​diretamente com algoritmos padrão quando o tipo de valor do iterador é charou signed char. Em vez disso, converta o valor para unsigned charprimeiro:

std::string str_tolower(std::string s) {
    std::transform(s.begin(), s.end(), s.begin(), 
                // static_cast<int(*)(int)>(std::tolower)         // wrong
                // [](int c){ return std::tolower(c); }           // wrong
                // [](char c){ return std::tolower(c); }          // wrong
                   [](unsigned char c){ return std::tolower(c); } // correct
                  );
    return s;
}
LF
fonte
3

Meu próprio modelo funciona, que executa maiúsculas / minúsculas.

#include <string>
#include <algorithm>

//
//  Lowercases string
//
template <typename T>
std::basic_string<T> lowercase(const std::basic_string<T>& s)
{
    std::basic_string<T> s2 = s;
    std::transform(s2.begin(), s2.end(), s2.begin(), tolower);
    return std::move(s2);
}

//
// Uppercases string
//
template <typename T>
std::basic_string<T> uppercase(const std::basic_string<T>& s)
{
    std::basic_string<T> s2 = s;
    std::transform(s2.begin(), s2.end(), s2.begin(), toupper);
    return std::move(s2);
}
TarmoPikaro
fonte
Era disso que eu precisava. Usei apenas towlowercaracteres largos que suportam o UTF-16.
Juv
2

Aqui está uma técnica de macro, se você quiser algo simples:

#define STRTOLOWER(x) std::transform (x.begin(), x.end(), x.begin(), ::tolower)
#define STRTOUPPER(x) std::transform (x.begin(), x.end(), x.begin(), ::toupper)
#define STRTOUCFIRST(x) std::transform (x.begin(), x.begin()+1, x.begin(),  ::toupper); std::transform (x.begin()+1, x.end(),   x.begin()+1,::tolower)

No entanto, observe que o comentário de @ AndreasSpindler sobre esta resposta ainda é uma consideração importante, no entanto, se você estiver trabalhando em algo que não é apenas caracteres ASCII.

Volomike
fonte
1
Estou com o voto negativo por fornecer macros quando existe uma solução perfeitamente boa - você até fornece essas soluções.
Clearer
2
A técnica de macro significa menos digitação de código para algo que normalmente se usaria muito em programação. Por que não usar isso? Caso contrário, por que ter macros?
Volomike
3
As macros são um legado do C que está sendo trabalhado duro para se livrar. Se você deseja reduzir a quantidade de digitação, use uma função ou uma lambda. void strtoupper(std::string& x) { std::transform (x.begin(), x.end(), x.begin(), ::toupper); }
Clearer
1
@Clearer Como eu quero ser um codificador melhor, você pode me fornecer qualquer link de documento ANSI em que algum comitê ANSI C ++ diga algo com o efeito de: "Precisamos convocar uma reunião para eliminar macros do C ++"? Ou algum outro roteiro?
Volomike
2
Não posso. A posição de Bjarne sobre o assunto foi esclarecida em várias ocasiões. Além disso, existem muitas razões para não usar macros em C e também em C ++. xpode ser uma expressão válida, que apenas compila corretamente, mas fornece resultados completamente falsos por causa das macros.
Clearer
2
// tolower example (C++)
#include <iostream>       // std::cout
#include <string>         // std::string
#include <locale>         // std::locale, std::tolower

int main ()
{
  std::locale loc;
  std::string str="Test String.\n";
  for (std::string::size_type i=0; i<str.length(); ++i)
    std::cout << std::tolower(str[i],loc);
  return 0;
}

Para mais informações: http://www.cplusplus.com/reference/locale/tolower/

MoraRockey
fonte
2

Existe uma alternativa que funcione 100% do tempo?

Não

Há várias perguntas que você precisa se perguntar antes de escolher um método em minúsculas.

  1. Como a string é codificada? ASCII simples? UTF-8? alguma forma de codificação herdada ASCII estendida?
  2. O que você quer dizer com letras minúsculas? As regras de mapeamento de caso variam entre os idiomas! Deseja algo que seja localizado na localidade dos usuários? Deseja algo que se comporte de maneira consistente em todos os sistemas em que o software é executado? Deseja apenas caracteres ASCII em minúsculas e passar por todo o resto?
  3. Quais bibliotecas estão disponíveis?

Depois de ter respostas para essas perguntas, você pode começar a procurar uma solução que atenda às suas necessidades. Não existe um tamanho único que funcione para todos em todos os lugares!

plugwash
fonte
2

Tente esta função :)

string toLowerCase(string str) {
    int str_len = str.length();
    string final_str = "";
    for(int i=0; i<str_len; i++) {
        char character = str[i];
        if(character>=65 && character<=92) {
            final_str += (character+32);
        } else {
            final_str += character;
        }
    }
    return final_str;
}
BuSaeed
fonte
1

Nas plataformas da Microsoft, você pode usar a strlwrfamília de funções: http://msdn.microsoft.com/en-us/library/hkxwh33z.aspx

// crt_strlwr.c
// compile with: /W3
// This program uses _strlwr and _strupr to create
// uppercase and lowercase copies of a mixed-case string.
#include <string.h>
#include <stdio.h>

int main( void )
{
   char string[100] = "The String to End All Strings!";
   char * copy1 = _strdup( string ); // make two copies
   char * copy2 = _strdup( string );

   _strlwr( copy1 ); // C4996
   _strupr( copy2 ); // C4996

   printf( "Mixed: %s\n", string );
   printf( "Lower: %s\n", copy1 );
   printf( "Upper: %s\n", copy2 );

   free( copy1 );
   free( copy2 );
}
Autodidata
fonte
0

Fragmento de código

#include<bits/stdc++.h>
using namespace std;


int main ()
{
    ios::sync_with_stdio(false);

    string str="String Convert\n";

    for(int i=0; i<str.size(); i++)
    {
      str[i] = tolower(str[i]);
    }
    cout<<str<<endl;

    return 0;
}
rashedcs
fonte
0

Copie porque não foi permitido melhorar a resposta. Obrigado SO


string test = "Hello World";
for(auto& c : test)
{
   c = tolower(c);
}

Explicação:

for(auto& c : test)é um loop for baseado em intervalo do tipo :
for (range_declaration:range_expression)loop_statement

  1. range_declaration: auto& c
    Aqui o especificador automático é usado para dedução automática de tipo. Portanto, o tipo é deduzido do inicializador de variáveis.

  2. range_expression: test
    O intervalo, neste caso, são os caracteres da string test.

Os caracteres da sequência testestão disponíveis como uma referência dentro do identificador de loop for c.

goulashsoup
fonte
Esclareça de onde você copiou sua resposta.
precisa saber é o seguinte
0

O C ++ não possui métodos tolower ou toupper implementados para string, mas está disponível para char. Pode-se facilmente ler cada caractere de string, convertê-lo no caso necessário e colocá-lo novamente em string. Um código de amostra sem usar nenhuma biblioteca de terceiros:

#include<iostream>

int main(){
  std::string str = std::string("How IS The Josh");
  for(char &ch : str){
    ch = std::tolower(ch);
  }
  std::cout<<str<<std::endl;
  return 0;
}

Para operação baseada em caracteres na sequência: Para cada caractere na sequência

Mahipal
fonte
-1

Esta poderia ser outra versão simples para converter maiúsculas em minúsculas e vice-versa. Usei a versão da comunidade VS2017 para compilar esse código fonte.

#include <iostream>
#include <string>
using namespace std;

int main()
{
    std::string _input = "lowercasetouppercase";
#if 0
    // My idea is to use the ascii value to convert
    char upperA = 'A';
    char lowerA = 'a';

    cout << (int)upperA << endl; // ASCII value of 'A' -> 65
    cout << (int)lowerA << endl; // ASCII value of 'a' -> 97
    // 97-65 = 32; // Difference of ASCII value of upper and lower a
#endif // 0

    cout << "Input String = " << _input.c_str() << endl;
    for (int i = 0; i < _input.length(); ++i)
    {
        _input[i] -= 32; // To convert lower to upper
#if 0
        _input[i] += 32; // To convert upper to lower
#endif // 0
    }
    cout << "Output String = " << _input.c_str() << endl;

    return 0;
}

Nota: se houver caracteres especiais, precisará ser tratado usando a verificação de condição.

Praveer Kumar
fonte
-8

Eu tentei std :: transform, tudo o que recebo é um abominável erro de compilação stl criptic que somente druidas de 200 anos atrás podem entender (não é possível converter de para flibidi flabidi flu)

isso funciona bem e pode ser facilmente ajustado

string LowerCase(string s)
{
    int dif='a'-'A';
    for(int i=0;i<s.length();i++)
    {
        if((s[i]>='A')&&(s[i]<='Z'))
            s[i]+=dif;
    }
   return s;
}

string UpperCase(string s)
{
   int dif='a'-'A';
    for(int i=0;i<s.length();i++)
    {
        if((s[i]>='a')&&(s[i]<='z'))
            s[i]-=dif;
    }
   return s;
}
fdsfdsfdsfds
fonte