Convertir letras a números en C

11 minutos de lectura

avatar de usuario
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!

  • 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

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

avatar de usuario
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.

avatar de usuario
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

avatar de usuario
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

avatar de usuario
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;

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad