Comment puis-je minuscule une chaîne en C?

108

Comment puis-je convertir une chaîne de casse mixte en chaîne en minuscules en C?

Tony Stark
la source
2
Avez-vous uniquement affaire à l'ASCII avec les lettres az?
Mark Byers
1
ascii. comment pourrais-je en tenir compte? l'exemple ci-dessous fonctionnerait-il toujours? que se passe-t-il si mon caractère est un '#' et que tolower () est appelé dessus?
Tony Stark
1
Ça marchera. Je me demandais plus si votre chaîne contenait des choses comme é ou Ü.
Mark Byers
1
Pourquoi ne pas simplement utiliser "strlwr"? strlwr((char*)str);Il passe simplement par la chaîne et le convertit lui-même.
Larry
1
@Larry Ce n'est pas standard.
mi

Réponses:

153

C'est dans la bibliothèque standard, et c'est le moyen le plus simple que je puisse voir pour implémenter une telle fonction. Alors oui, faites une boucle sur la chaîne et convertissez chaque caractère en minuscules.

Quelque chose de trivial comme ça:

#include <ctype.h>

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

ou si vous préférez une doublure, vous pouvez utiliser celle-ci de JF Sebastian:

for ( ; *p; ++p) *p = tolower(*p);
Earlz
la source
35
for ( ; *p; ++p) *p = tolower(*p);semble plus idiomatique.
jfs
14
@JF, voilà. Cela dépend s'ils veulent que le code soit effrayant ou agréable :) (une doublure très lisible, mais cela semble effrayant)
Earlz
cela me donne un segfault si str est un char *, mais pas si str est un tableau de caractères. Vous avez une explication à cela?
Café électrique du
1
Je crois que la seule ligne vous fera perdre votre pointeur sur la chaîne.
Ace.C
2
Je crois qu'un seul paquebot aura des ramifications incalculables.
NOP da CALL
7

convertir en minuscules équivaut à augmenter le bit 0x60 si vous vous limitez à ASCII:

for(char *p = pstr; *p; ++p)
    *p = *p > 0x40 && *p < 0x5b ? *p | 0x60 : *p;
Oleg Razgulyaev
la source
6
Pour le rendre un peu plus lisible, vous pouvez le fairefor(char *p = pstr;*p;++p) *p=*p>='A'&&*p<='Z'?*p|0x60:*p;
Grant Peters
7
Cette version est en fait plus lente que celle de la glibc tolower(). 55,2 contre 44,15 sur ma machine.
jfs
je ne peux pas imaginer que: tolower () traite des caractères; seulement si c'est macro
Oleg Razgulyaev
1
@oraz: tolower () a une int (*)(int)signature. Voici le code utilisé pour les mesures de performance gist.github.com/370497
jfs
@JF: je vois, ils ont utilisé la table, mais je peux optimiser: for (; * p; ++ p) if (* p> 'Z') {continue;} else if (* p <'A') {continue;} else {* p = * p | 0x60;}
Oleg Razgulyaev
1

Êtes-vous uniquement confronté à des chaînes ASCII et n'avez-vous aucun problème de paramètres régionaux? Alors oui, ce serait une bonne façon de le faire.

Mark Byers
la source
que se passe-t-il si tolower () est appelé sur un caractère az non ascii? comme '!' ou '#'. Je l'ai testé sur «#» et cela a semblé fonctionner correctement. est-ce généralement vrai pour tous les caractères ascii qui ne sont pas des lettres az?
Tony Stark
1
@hatorade: tolower()laisse l'argument inchangé s'il n'est pas dans la plage 'A' .. 'Z'.
jfs
1
! et # sont tous deux des caractères ascii. Mark faisait référence à d'autres encodages comme UTF8, où vous ne pouvez pas supposer qu'il y a un octet par caractère (comme le fait cette solution)
hdgarrood
1

Si vous avez besoin de la prise en charge d'Unicode dans la fonction minuscule, consultez cette question: Bibliothèque Unicode Light C

Eduardo
la source
1

Si nous allons être aussi bâclés à utiliser tolower(), faites ceci:

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

Mais bon, ça explose un peu si vous lui donnez des symboles / chiffres, et en général c'est mal. Bonne question d'entretien, cependant.

Ken S
la source
6
Oui, cela pliera / broche / mutilera une variété de symboles (en ASCII, tout symbole, caractère de contrôle ou chiffre avec le bit 5 clair deviendra le même code de caractère avec le bit 5 défini, etc.) donc vraiment, sérieusement, ne le faites pas utilise le.
Ken S
Ce message est discuté sur meta .
Patrick Hofman
0

Boucler le pointeur pour obtenir de meilleures performances:

#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
la source