¿Cómo pongo en minúscula una cadena en C?

108

¿Cómo puedo convertir una cadena de mayúsculas y minúsculas en una cadena en minúsculas en C?

Tony Stark
fuente
2
¿Está tratando con ASCII solo con letras az?
Mark Byers
1
ascii. ¿Cómo lo tomaría en cuenta? ¿Funcionaría el siguiente ejemplo? ¿Qué sucede si mi char es un '#' y se llama a tolower ()?
Tony Stark
1
Que funcionará. Estaba más pensando si tu cadena contiene cosas como é o Ü.
Mark Byers
1
¿Por qué no usar simplemente "strlwr"? strlwr((char*)str);Simplemente pasa por la cadena y la convierte.
Larry
1
@Larry No es estándar.
mediados

Respuestas:

153

Está en la biblioteca estándar, y esa es la forma más sencilla que puedo ver para implementar dicha función. Así que sí, simplemente recorra la cadena y convierta cada carácter a minúsculas.

Algo trivial como esto:

#include <ctype.h>

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

o si prefieres one liners, entonces puedes usar este de JF Sebastian:

for ( ; *p; ++p) *p = tolower(*p);
Earlz
fuente
35
for ( ; *p; ++p) *p = tolower(*p);parece más idiomático.
jfs
14
@JF ahí tienes. Depende de si quieren que el código se vea aterrador o agradable :) (una línea muy legible, pero da miedo)
Earlz
esto me da un segfault si str es un char *, pero no si str es una matriz de caracteres. ¿Tienes alguna explicación para eso?
Café eléctrico
1
Creo que la única línea hará que pierdas el puntero de la cuerda.
Ace.C
2
Creo que un trazador de líneas tendrá ramificaciones incalculables.
NOP da CALL
7

convertir a minúsculas equivale a subir el bit 0x60 si se limita a ASCII:

for(char *p = pstr; *p; ++p)
    *p = *p > 0x40 && *p < 0x5b ? *p | 0x60 : *p;
Oleg Razgulyaev
fuente
6
Para hacerlo un poco más legible, podría hacerlofor(char *p = pstr;*p;++p) *p=*p>='A'&&*p<='Z'?*p|0x60:*p;
Grant Peters
7
Esta versión es más lenta que la de glibc tolower(). 55.2 vs 44.15 en mi máquina.
jfs
no puedo imaginar que: tolower () se ocupa de los caracteres; solo si es macro
Oleg Razgulyaev
1
@oraz: tolower () tiene int (*)(int)firma. Aquí está el código utilizado para las mediciones de rendimiento gist.github.com/370497
jfs
@JF: ya veo, han usado tablas, pero puedo optimizar: for (; * p; ++ p) if (* p> 'Z') {continue;} else if (* p <'A') {continue;} else {* p = * p | 0x60;}
Oleg Razgulyaev
1

¿Está tratando con cadenas ASCII y no tiene problemas de configuración regional? Entonces sí, esa sería una buena forma de hacerlo.

Mark Byers
fuente
¿Qué sucede si se llama a tolower () en un carácter az no ascii? me gusta '!' o '#'. Lo probé en '#' y pareció funcionar bien. ¿Es esto generalmente cierto para todos los caracteres ascii que no son letras az?
Tony Stark
1
@hatorade: tolower()deja el argumento sin cambios si no está en el rango 'A' .. 'Z'.
jfs
1
! y # son caracteres ascii. Mark se refería a otras codificaciones como UTF8, donde no se puede asumir que hay un byte por carácter (como lo hace esta solución)
hdgarrood
1

Si vamos a ser tan descuidados en el uso tolower(), haga esto:

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

Pero bueno, explota un poco si le das algunos símbolos / números, y en general es malvado. Sin embargo, es una buena pregunta para la entrevista.

Ken S
fuente
6
Sí, esto plegará / girará / mutilará una variedad de símbolos (en ASCII, cualquier símbolo, carácter de control o numeral con el bit 5 limpio se convertirá en el mismo código de carácter con el bit 5 configurado, etc.) así que realmente, en serio, no lo hagas úselo.
Ken S
Esta publicación se analiza en meta .
Patrick Hofman
0

Hacer un bucle con el puntero para obtener un mejor rendimiento:

#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
fuente