Estoy tratando de escribir un código que convierta letras en números. Por ejemplo A ==> 0 B ==> 1 C ==> 2 y así sucesivamente. Estoy pensando en escribir 26 sentencias if. Me pregunto si hay una mejor manera de hacer esto…
¡Gracias!
usuario133466
Estoy tratando de escribir un código que convierta letras en números. Por ejemplo A ==> 0 B ==> 1 C ==> 2 y así sucesivamente. Estoy pensando en escribir 26 sentencias if. Me pregunto si hay una mejor manera de hacer esto…
¡Gracias!
Esta es una manera que siento que es mejor que la switch
y, sin embargo, cumple con los estándares (no asume ASCII):
#include <string.h>
#include <ctype.h>
/* returns -1 if c is not an alphabetic character */
int c_to_n(char c)
{
int n = -1;
static const char * const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *p = strchr(alphabet, toupper((unsigned char)c));
if (p)
{
n = p - alphabet;
}
return n;
}
Para el cumplimiento total de los estándares, es posible que desee lanzar p - alphabet
antes de asignarlo. Podrías usar un ptrdiff_t
o algún otro tipo técnicamente correcto, pero dadas las limitaciones de rango, no creo que sea realmente necesario. Se garantiza que cualquier tipo de integral podrá contener cualquiera de los valores que estamos usando aquí.
– Chris Lutz
24 de septiembre de 2009 a las 18:58
Sí, en este caso podemos garantizar que p - alphabet
está en el rango 0…25, por lo que definitivamente encajará en un int
. No creo que sea necesario un molde allí: la semántica de asignar un tipo integral a otro está bastante bien definida.
– café
24 de septiembre de 2009 a las 22:59
Te daré un voto por ese @caf, ya que maneja todos los conjuntos de caracteres dentro del estándar. También es una de las raras ocasiones en las que he visto a alguien usar la const const correctamente para puntero y pointee 🙂 Por supuesto, siendo un veterano, simplemente habría hecho: ‘return p ? (int)(p – alfabeto) : -1;’ en lugar de todas esas tonterías con las declaraciones n e if.
– pax diablo
5 de noviembre de 2009 a las 2:41
Si necesita lidiar con mayúsculas y minúsculas, es posible que desee hacer algo como:
if (letter >= 'A' && letter <= 'Z')
num = letter - 'A';
else if (letter >= 'a' && letter <= 'z')
num = letter - 'a';
Si desea mostrarlos, querrá convertir el número en un valor ASCII agregándole un ‘0’:
asciinumber = num + '0';
Alternativamente, utilice num = toupper(letter) - 'A'
para convertir la letra a mayúscula, evitando así el condicional. los toupper()
La función se encuentra en el ctype.h
encabezamiento.
– Chris Lutz
24 de septiembre de 2009 a las 4:14
También podemos notar que las letras minúsculas son solo un 0x20
diferencia de mayúsculas.
– Seda del mediodía
24 de septiembre de 2009 a las 4:14
Es cierto, pero al tener un condicional, si necesita diferenciar de alguna manera, puede hacerlo, pero hay varias opciones, solo quería señalar que las mayúsculas y minúsculas pueden ser un problema y deben manejarse.
– James Negro
24 de septiembre de 2009 a las 4:16
Por supuesto. Pondría este código en una función y agregaría un else num = -1
al final solo por seguridad, pero no importa. Puede comprobar que el valor de retorno de toupper() - 'A'
está dentro del rango deseado (0 – 25) con la misma facilidad.
– Chris Lutz
24 de septiembre de 2009 a las 4:20
Tenga en cuenta que el “número ascii = num + ‘0’;” bit solo funciona para un solo dígito.
– Tal Pressman
24 de septiembre de 2009 a las 4:45
usuario3386109
El estándar C no garantiza que los caracteres del alfabeto se numeren secuencialmente. Por lo tanto, el código portable no puede asumir, por ejemplo, que 'B'-'A'
es igual a 1.
La sección relevante de la especificación C es la sección 5.2.1 que describe los conjuntos de caracteres:
3 Tanto el juego de caracteres de fuente básica como el de ejecución básica tendrán los siguientes miembros: el 26 letras mayúsculas del alfabeto latino
ABCDEFGHIJKLM NOPQRSTUVWXYZ
el 26 letras minusculas del alfabeto latino
abcdefghijklm nopqrstuvwxyz
el 10 decimal dígitos
0123456789
los siguientes 29 caracteres gráficos
!"#%&'()*+,-./: ;<=>?[\]^_{|}~
el carácter de espacio y los caracteres de control que representan la pestaña horizontal, la pestaña vertical y el avance de página. La representación de cada miembro de los conjuntos de caracteres básicos de origen y ejecución debe caber en un byte. Tanto en el juego de caracteres básicos de origen como en el de ejecución, el valor de cada carácter después del 0 en la lista anterior de dígitos decimales será uno mayor que el valor del anterior.
Entonces, la especificación solo garantiza que los dígitos tendrán codificaciones secuenciales. No hay absolutamente ninguna restricción sobre cómo se codifican los caracteres alfabéticos.
Afortunadamente, existe una manera fácil y eficiente de convertir A en 0, B en 1, etc. Aquí está el código
char letter="E"; // could be any upper or lower case letter
char str[2] = { letter }; // make a string out of the letter
int num = strtol( str, NULL, 36 ) - 10; // convert the letter to a number
La razón por la que esto funciona se puede encontrar en la página del manual para strtol
Que estados:
(En bases superiores a 10, la letra ‘A’ en mayúsculas o minúsculas representa 10, ‘B’ representa 11 y así sucesivamente, con ‘Z’ representando 35).
Así que pasando 36 a strtol
como dice la base strtol
para convertir 'A'
o 'a'
a 10, 'B'
o 'b'
a 11, y así sucesivamente. Todo lo que necesitas hacer es restar 10 para obtener la respuesta final.
Hay una manera mucho mejor.
En ASCII (www.asciitable.com) puede conocer los valores numéricos de estos caracteres.
‘A’ es 0x41.
Así que simplemente puede restarles 0x41 para obtener los números. No sé c muy bien, pero algo como:
int num = 'A' - 0x41;
Deberia trabajar.
chris lutz
Otro, mucho peor (pero aún mejor que 26 if
sentencias) la alternativa es usar switch
/case
:
switch(letter)
{
case 'A':
case 'a': // don't use this line if you want only capital letters
num = 0;
break;
case 'B':
case 'b': // same as above about 'a'
num = 1;
break;
/* and so on and so on */
default:
fprintf(stderr, "WTF?\n");
}
Considere esto solo si no hay absolutamente ninguna relación entre la letra y su código. Dado que existe una clara relación secuencial entre la letra y el código en su caso, usar esto es bastante tonto y será terrible de mantener, pero si tuviera que codificar caracteres aleatorios en valores aleatorios, esta sería la forma de evitar escribir. un trillón if()
/else if()
/else if()
/else
declaraciones.
Esto es no tan tonto. A pesar de su comentario en otro lugar, @Chris, C99 solo exige que los caracteres numéricos estén en orden. Los alfas pueden estar por todas partes (como EBCDIC con sus dos áreas diferentes). Esta es, de hecho, la única respuesta correcta hasta la fecha. + 1.
– pax diablo
24 de septiembre de 2009 a las 5:04
ah Estoy por todo el camino hoy. Sabía que los dígitos estaban en orden, solo di un salto sobre los caracteres. Realmente necesito leer el estándar C. Sin embargo, tengo que decir que si este es el precio de la corrección, estoy dispuesto a decir “¡Al diablo!” con EBCDIC.
– Chris Lutz
24 de septiembre de 2009 a las 5:11
Es bueno que todos sepan que el orden no está garantizado, pero en serio, debes tener en cuenta a tu audiencia. Si este programa va a ser utilizado por personas que se ejecutan en cualquier computadora ‘estándar’, es seguro usar “letra – ‘A'”
– Ed S.
24 de septiembre de 2009 a las 6:25
@ed: Mi audiencia (¿visual?) consiste en personas que conocen y siguen el estándar (y ese es el estándar sin citas). Su programa no se ajustaría al estándar. Está bien, entiendo que la gran mayoría de los entornos C usan ASCII o ISO646, pero considero un poco arrogante afirmar que eso es todo lo que importa. ISO dejó abierta la posibilidad de letras no contiguas por una buena razón: ¿realmente cree que sabe más que ellos? No quiero entrar en una pelea de mierda, solo expongo mi punto de vista; es posible que tengamos que estar de acuerdo en estar en desacuerdo.
– pax diablo
24 de septiembre de 2009 a las 7:43
jim dennis
En la mayoría de los lenguajes de programación y secuencias de comandos, existe un medio para obtener el valor “ordinal” de cualquier carácter. (Piense en ello como un desplazamiento desde el comienzo del conjunto de caracteres).
Por lo tanto, normalmente puedes hacer algo como:
for ch in somestring:
if lowercase(ch):
n = ord(ch) - ord ('a')
elif uppercase(ch):
n = ord(ch) - ord('A')
else:
n = -1 # Sentinel error value
# (or raise an exception as appropriate to your programming
# environment and to the assignment specification)
Por supuesto, esto no funcionaría para un sistema basado en EBCDIC (y podría no funcionar para otros conjuntos de caracteres exóticos). Supongo que una comprobación de cordura razonable sería probar que esta función devuelve valores monótonamente crecientes en el rango de 0 a 26 para las cadenas “abc…xzy” y “ABC…XYZ”).
Un enfoque completamente diferente sería crear una matriz asociativa (diccionario, tabla, hash) de sus letras y sus valores (uno o dos bucles simples). Entonces usa eso. (La mayoría de los lenguajes de programación modernos incluyen soporte para matrices asociativas.
Naturalmente, no estoy “haciendo tu tarea”. Tendrás que hacerlo por ti mismo. Simplemente estoy explicando que esos son los enfoques obvios que usaría cualquier programador profesional. (Está bien, un truco del lenguaje ensamblador también podría enmascarar un bit para cada byte).
Esto es no tan tonto. A pesar de su comentario en otro lugar, @Chris, C99 solo exige que los caracteres numéricos estén en orden. Los alfas pueden estar por todas partes (como EBCDIC con sus dos áreas diferentes). Esta es, de hecho, la única respuesta correcta hasta la fecha. + 1.
– pax diablo
24 de septiembre de 2009 a las 5:04
ah Estoy por todo el camino hoy. Sabía que los dígitos estaban en orden, solo di un salto sobre los caracteres. Realmente necesito leer el estándar C. Sin embargo, tengo que decir que si este es el precio de la corrección, estoy dispuesto a decir “¡Al diablo!” con EBCDIC.
– Chris Lutz
24 de septiembre de 2009 a las 5:11
Es bueno que todos sepan que el orden no está garantizado, pero en serio, debes tener en cuenta a tu audiencia. Si este programa va a ser utilizado por personas que se ejecutan en cualquier computadora ‘estándar’, es seguro usar “letra – ‘A'”
– Ed S.
24 de septiembre de 2009 a las 6:25
@ed: Mi audiencia (¿visual?) consiste en personas que conocen y siguen el estándar (y ese es el estándar sin citas). Su programa no se ajustaría al estándar. Está bien, entiendo que la gran mayoría de los entornos C usan ASCII o ISO646, pero considero un poco arrogante afirmar que eso es todo lo que importa. ISO dejó abierta la posibilidad de letras no contiguas por una buena razón: ¿realmente cree que sabe más que ellos? No quiero entrar en una pelea de mierda, solo expongo mi punto de vista; es posible que tengamos que estar de acuerdo en estar en desacuerdo.
– pax diablo
24 de septiembre de 2009 a las 7:43
sbi
Dado que el tipo de datos char se trata de forma similar a un tipo de datos int en C y C++, podría optar por algo como:
char c="A"; // just some character
int urValue = c - 65;
Si le preocupa la distinción entre mayúsculas y minúsculas:
#include <ctype.h> // if using C++ #include <cctype>
int urValue = toupper(c) - 65;
Solo una nota rápida para toda esa multitud de “num = letra – ‘A'”. El estándar C99 requiere que los dígitos (‘0’-‘9’) sean consecutivos pero no los caracteres de las letras: “Tanto en los juegos de caracteres básicos de origen como de ejecución, el valor de cada carácter después del 0 en la lista anterior de dígitos decimales será uno mayor que el valor del anterior”. EBCDIC (con su extraño alfabeto inconexo) es perfectamente válido. Eso significa que @ChrisLutz tiene la única respuesta correcta hasta la fecha, a pesar de sus dudas al respecto 🙂
– pax diablo
24 de septiembre de 2009 a las 5:05
ISO debería haber ordenado ASCII (o al menos letras secuenciales), pero sospecho que IBM tuvo un papel importante que desempeñar para mantener la conformidad de sus compiladores C de mainframe.
– pax diablo
24 de septiembre de 2009 a las 5:06
Levante la mano si tiene, hace o alguna vez desarrollará para una máquina EBCDIC.
– Crashworks
24 de septiembre de 2009 a las 5:10
En cualquier caso, no importar cuantas personas lo hacen El estándar no requiere letras consecutivas, por lo que los implementadores son libres de hacer lo que deseen. Las personas que codifican según el estándar ASCII están limitando seriamente su mercado potencial a solo alrededor del 99,999% de las computadoras que existen 🙂
– pax diablo
24 de septiembre de 2009 a las 5:15
Si esto es realmente una tarea escolar, debe preocuparse si su maestro se preocupa o incluso sabe acerca de los problemas del estándar C99. De lo contrario, podría darte una calificación peor solo porque no usas el enfoque “más limpio” (es decir, letra – ‘A’), y discutir sobre los estándares C99 no será suficiente para convencerlo.
– djeidot
24 de septiembre de 2009 a las 14:19