Como faço para minúsculas uma string em C?

108

Como posso converter uma string de maiúsculas e minúsculas em uma string de letras minúsculas em C?

Tony Stark
fonte
2
Você está lidando apenas com ASCII com letras az apenas?
Mark Byers,
1
ascii. como eu levaria isso em consideração? o exemplo abaixo ainda funcionaria? o que acontece se meu char for um '#' e tolower () for chamado?
Tony Stark
1
Isso vai funcionar. Eu estava mais pensando se sua string contém coisas como é ou Ü.
Mark Byers de
1
Por que não usar apenas "strlwr"? strlwr((char*)str);Ele simplesmente passa pela string e se converte.
Larry
1
@Larry Não é padrão.
meados de

Respostas:

153

Está na biblioteca padrão, e essa é a maneira mais direta que posso ver para implementar essa função. Então, sim, apenas percorra a string e converta cada caractere em minúsculas.

Algo trivial como isto:

#include <ctype.h>

for(int i = 0; str[i]; i++){
  str[i] = tolower(str[i]);
}

ou se você preferir um forro, pode usar este de JF Sebastian:

for ( ; *p; ++p) *p = tolower(*p);
Earlz
fonte
35
for ( ; *p; ++p) *p = tolower(*p);parece mais idiomático.
jfs de
14
@JF aí está. Depende se eles querem que o código pareça assustador ou legal :) (um liner muito legível, mas parece assustador)
Earlz
isso me dá um segfault se str for a char *, mas não se str for uma matriz char. Tem alguma explicação para isso?
Café Elétrico de
1
Acredito que o único forro fará com que você perca o indicador da corda.
Ace.C
2
Eu acredito que um forro terá ramificações incalculáveis.
NOP da CALL
7

converter para minúsculas é equivalente a aumentar o bit 0x60 se você se restringir a ASCII:

for(char *p = pstr; *p; ++p)
    *p = *p > 0x40 && *p < 0x5b ? *p | 0x60 : *p;
Oleg Razgulyaev
fonte
6
Para torná-lo um pouco mais legível, você pode fazerfor(char *p = pstr;*p;++p) *p=*p>='A'&&*p<='Z'?*p|0x60:*p;
Grant Peters,
7
Esta versão é realmente mais lenta que a da glibc tolower(). 55,2 vs. 44,15 na minha máquina.
jfs
não consigo imaginar que: tolower () lida com chars; somente se for macro
Oleg Razgulyaev
1
@oraz: tolower () tem int (*)(int)assinatura. Aqui está o código usado para medições de desempenho gist.github.com/370497
jfs
@JF: vejo, eles usaram a tabela, mas posso otimizar: for (; * p; ++ p) if (* p> 'Z') {continue;} else if (* p <'A') {continue;} else {* p = * p | 0x60;}
Oleg Razgulyaev
1

Você está lidando apenas com strings ASCII e não tem problemas de localidade? Então, sim, seria uma boa maneira de fazer isso.

Mark Byers
fonte
o que acontece se tolower () for chamado em um char não ascii az? gostar '!' ou '#'. Eu testei em '#' e pareceu funcionar bem. Isso geralmente é verdadeiro para todos os caracteres ascii que não são letras az?
Tony Stark
1
@hatorade: tolower()deixa o argumento inalterado se não estiver no intervalo 'A' .. 'Z'.
jfs de
1
! e # são ambos caracteres ascii. Mark estava se referindo a outras codificações como UTF8, onde você não pode presumir que há um byte por caractere (como esta solução faz)
hdgarrood
1

Se você precisar de suporte Unicode na função de minúsculas, consulte esta pergunta: Light C Unicode Library

Eduardo
fonte
1

Se vamos ser tão desleixados quanto no uso tolower(), faça o seguinte:

char blah[] = "blah blah Blah BLAH blAH\0"; int i=0; while(blah[i]|=' ', blah[++i]) {}

Mas, bem, meio que explode se você alimentá-lo com alguns símbolos / numerais, e em geral é maléfico. Boa pergunta para a entrevista, no entanto.

Ken S
fonte
6
Sim, isso irá dobrar / fuso / mutilar uma variedade de símbolos (em ASCII, qualquer símbolo, caractere de controle ou numeral com bit 5 apagado se tornará o mesmo código de caractere com bit 5 definido, etc), então realmente, sério, não use-o.
Ken S
Este post é discutido no meta .
Patrick Hofman,
0

Loop do ponteiro para obter melhor desempenho:

#include <ctype.h>

char* toLower(char* s) {
  for(char *p=s; *p; p++) *p=tolower(*p);
  return s;
}
char* toUpper(char* s) {
  for(char *p=s; *p; p++) *p=toupper(*p);
  return s;
}
cscan
fonte