Usando traductor de código Morse en C

Traductor de código Morse en C

En este post vamos a implementar un traductor de código Morse en C. Veremos cómo codificar o transformar código Morse usando el lenguaje C.

Por ejemplo, haremos que la palabra HOLA se convierta a su equivalente .... --- .-.. .- y viceversa, logrando al final un traductor Morse.

Las equivalencias

Cada letra tiene un código que lo representa; yo me he basado en el siguiente archivo que contiene la equivalencia de cada letra con su respectivo código.

Signo,Código
A,.-
B,-...
C,-.-.
CH,----
D,-..
E,.
F,..-.
G,--.
H,....
I,..
J,.---
K,-.-
L,.-..
M,--
N,-.
Ñ,--.--
O,---
P,.--.
Q,--.-
R,.-.
S,...
T,-
U,..-
V,...-
W,.--
X,-..-
Y,-.--
Z,--..
0,-----
1,.----
2,..---
3,...--
4,....-
5,.....
6,-....
7,--...
8,---..
9,----.
.,.-.-.-
",",--..--
:,---...
?,..--..
',.----.
-,-....-
/,-..-.
comilla doble,.-..-.
@,.--.-.
=,-...-
!,−.−.−−

El algoritmo del traductor de Morse a C

Esto es muy simple, solo hay que buscar la equivalencia de cada letra o de cada código Morse; para ello podemos tomar varios enfoques pero yo he elegido el de poner dos arreglos; uno con Morse y otro con ASCII, con cada valor equivalente en el mismo índice:

// Código y signo iguales deben estar en el mismo índice
char *codigosMorse[] = {
        ".-", "-...", "-.-.", "-..",
        ".", "..-.", "--.", "....", "..",
        ".---", "-.-", ".-..", "--", "-.",
        "---", ".--.", "--.-", ".-.", "...",
        "-", "..-", "...-", ".--", "-..-",
        "-.--", "--..", "-----", ".----", "..---",
        "...--", "....-", ".....", "-....", "--...",
        "---..", "----.", ".-.-.-", "--..--", "---...",
        "..--..", ".----.", "-....-", "-..-.", ".--.-.",
        "-...-", ".-..-.", "-.-.--",};

char *simbolosAscii[] = {"A", "B", "C", "D",
                         "E", "F", "G", "H", "I",
                         "J", "K", "L", "M", "N",
                         "O", "P", "Q", "R", "S",
                         "T", "U", "V", "W", "X",
                         "Y", "Z", "0", "1", "2",
                         "3", "4", "5", "6", "7",
                         "8", "9", ".", ",", ":",
                         "?", "'", "-", "/", "@",
                         "=", "\"", "!",};

Por ejemplo, la letra A equivale a .- y el símbolo ! equivale a -.-.--, están en distintos arreglos pero misma posición.

  • Cada que se quiere convertir de Morse a ASCII se busca el índice del código Morse a transformar, y luego se accede con ese índice pero al arreglo de simbolosAscii.
  • Lo mismo para transformar de ASCII a Morse, se busca el índice del símbolo ASCII y se accede al arreglo codigosMorse.

Esto sería más fácil si en C existieran los diccionarios, pero no existen y su implementación es cuestión de otro post.

Nota: otro enfoque más óptimo (en cuanto a rendimiento, para no buscar el elemento por cada símbolo) sería usar múltiples sentencias if o un diccionario.

Nota 2: si notas el algoritmo muy pesado, la verdad es que no lo es, lo pesado o complejo es trabajar con cadenas en C; si esto fuera otro lenguaje con mayor soporte de strings, nos llevaría menos de la mitad de código hacer el traductor de código Morse.

Funciones y ayudantes del traductor de Código Morse en C

Necesitamos funciones para dividir el algoritmo y hacerlo más fácil de resolver. También viene bien saber la longitud del arreglo, la cual se calcula así:

const int NUMERO_CODIGOS = sizeof(codigosMorse) / sizeof(codigosMorse[0]);

Lo calculamos con cualquier arreglo porque se supone que ambos arreglos miden lo mismo.

Después necesitamos el índice de cada código Morse o cada código ASCII:

int buscarIndiceDeMorse(char *codigo) {
    for (int x = 0; x < NUMERO_CODIGOS; x++) {
        if (strcmp(codigosMorse[x], codigo) == 0) {
            return x;
        }
    }
    return -1;
}

int buscarIndiceDeAscii(char signo) {
    // Convertir char a string
    char cadenaTemporal[2];
    cadenaTemporal[0] = signo;
    cadenaTemporal[1] = '\0';
    for (int x = 0; x < NUMERO_CODIGOS; x++) {
        if (strcmp(simbolosAscii[x], cadenaTemporal) == 0) {
            return x;
        }
    }
    return -1;
}

Son funciones que simplemente devuelven el índice del símbolo o código.

En la función para buscar el índice del código ascii creamos una cadena temporal, o mejor dicho, lo que equivale a una cadena o string en C, esto es para que strcmp (que compara cadenas) funcione.

Codificar Morse con C

Ahora veamos la siguiente función que convierte un mensaje a su equivalente en Morse. Leemos el mensaje con fgets y luego simplemente imprimimos cada equivalencia:

void demostrarCodificacionMorse() {
//    char mensaje[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,:?'-/@=\"!";
    char mensaje[LONGITUD_MENSAJE];
    printf("Mensaje a transformar en Morse: \n");
    fgets(mensaje, LONGITUD_MENSAJE, stdin);
    mensaje[strcspn(mensaje, "\r\n")] = 0; // Remover salto de línea
    // Recorremos la cadena y transformamos cada letra
    int i = 0;
    while (mensaje[i]) {
        // Convertir a mayúscula porque tenemos equivalencias solo para mayúsculas
        // y Morse no especifica minúscula
        char letraEnMayuscula = (char) toupper(mensaje[i]);
        int indice = buscarIndiceDeAscii(letraEnMayuscula);
        char *codigoMorse = codigosMorse[indice];
        // Aquí puedes hacer lo que gustes con el morse, yo simplemente lo imprimo
        printf("%s ", codigoMorse);
        i++;
    }
}

Estamos convirtiendo a mayúscula cada letra o símbolo pues en las equivalencias todo está en mayúscula. Cuando tenemos el código Morse lo imprimimos; como lo dije, puedes hacer cualquier cosa con él.

Decodificar Morse con C

Como queremos que este sea un traductor de código Morse en C necesitamos también decodificar un mensaje en Morse.

Para esto, vamos a hacer que cada símbolo Morse esté separado por un espacio; luego usamos strtok (algo como el split de C) y separamos la cadena por espacios.

void demostrarDecodificacionMorse() {
//    char mensaje[] = ".- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- -. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --.. ----- .---- ..--- ...-- ....- ..... -.... --... ---.. ----. .-.-.- --..-- ---... ..--.. .----. -....- -..-. .--.-. -...- .-..-. -.-.--";
    // Aquí define tu mensaje separado por espacios
    char mensaje[LONGITUD_MENSAJE];
    printf("Mensaje Morse a decodificar:\n");
    fgets(mensaje, LONGITUD_MENSAJE, stdin);
    mensaje[strcspn(mensaje, "\r\n")] = 0; // Remover salto de línea
    char delimitador[] = " ";
    // Separamos la cadena por espacios. Más información sobre strtok en https://parzibyte.me/blog/2018/11/13/separar-cadena-delimitadores-c-strtok/
    char *token = strtok(mensaje, delimitador);
    if (token != NULL) {
        while (token != NULL) {
            // Obtener cuál índice tiene este código
            int indice = buscarIndiceDeMorse(token);
            // Aquí puedes hacer lo que gustes con el ascii, yo simplemente lo imprimo
            char *ascii = simbolosAscii[indice];
            printf("%s", ascii);
            token = strtok(NULL, delimitador);
        }
    }
}

Ahora hacemos casi lo mismo, solo que agregamos la implementación para separar la cadena. Después obtenemos el índice con buscarIndiceDeMorse y lo usamos para acceder a simbolosAscii; al resultado final (ascii) lo imprimimos con printf.

Código completo del traductor de código Morse en C

Ahora veamos el código completo; ya lo he explicado por partes. Todo está dividido en funciones que se invocan desde otros métodos o desde la función main.

#include <stdio.h> // Para printf
#include <string.h> // Para strcmp y strlen
#include <ctype.h> // Para toupper

#define LONGITUD_MENSAJE 500
/**
 * Traductor de código Morse en C
 *
 * Basado en https://parzibyte.me/blog/2019/10/20/traductor-codigo-morse-c/
 *
 * @author parzibyte
 * https://parzibyte.me/blog
 *
 * */
// Código y signo iguales deben estar en el mismo índice
char *codigosMorse[] = {
        ".-", "-...", "-.-.", "-..",
        ".", "..-.", "--.", "....", "..",
        ".---", "-.-", ".-..", "--", "-.",
        "---", ".--.", "--.-", ".-.", "...",
        "-", "..-", "...-", ".--", "-..-",
        "-.--", "--..", "-----", ".----", "..---",
        "...--", "....-", ".....", "-....", "--...",
        "---..", "----.", ".-.-.-", "--..--", "---...",
        "..--..", ".----.", "-....-", "-..-.", ".--.-.",
        "-...-", ".-..-.", "-.-.--",};

char *simbolosAscii[] = {"A", "B", "C", "D",
                         "E", "F", "G", "H", "I",
                         "J", "K", "L", "M", "N",
                         "O", "P", "Q", "R", "S",
                         "T", "U", "V", "W", "X",
                         "Y", "Z", "0", "1", "2",
                         "3", "4", "5", "6", "7",
                         "8", "9", ".", ",", ":",
                         "?", "'", "-", "/", "@",
                         "=", "\"", "!",};

const int NUMERO_CODIGOS = sizeof(codigosMorse) / sizeof(codigosMorse[0]);

int buscarIndiceDeMorse(char *codigo) {
    for (int x = 0; x < NUMERO_CODIGOS; x++) {
        if (strcmp(codigosMorse[x], codigo) == 0) {
            return x;
        }
    }
    return -1;
}

int buscarIndiceDeAscii(char signo) {
    // Convertir char a string
    char cadenaTemporal[2];
    cadenaTemporal[0] = signo;
    cadenaTemporal[1] = '\0';
    for (int x = 0; x < NUMERO_CODIGOS; x++) {
        if (strcmp(simbolosAscii[x], cadenaTemporal) == 0) {
            return x;
        }
    }
    return -1;
}

void demostrarCodificacionMorse() {
//    char mensaje[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,:?'-/@=\"!";
    char mensaje[LONGITUD_MENSAJE];
    printf("Mensaje a transformar en Morse: \n");
    fgets(mensaje, LONGITUD_MENSAJE, stdin);
    mensaje[strcspn(mensaje, "\r\n")] = 0; // Remover salto de línea
    // Recorremos la cadena y transformamos cada letra
    int i = 0;
    while (mensaje[i]) {
        // Convertir a mayúscula porque tenemos equivalencias solo para mayúsculas
        // y Morse no especifica minúscula
        char letraEnMayuscula = (char) toupper(mensaje[i]);
        int indice = buscarIndiceDeAscii(letraEnMayuscula);
        char *codigoMorse = codigosMorse[indice];
        // Aquí puedes hacer lo que gustes con el morse, yo simplemente lo imprimo
        printf("%s ", codigoMorse);
        i++;
    }
}

void demostrarDecodificacionMorse() {
//    char mensaje[] = ".- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- -. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --.. ----- .---- ..--- ...-- ....- ..... -.... --... ---.. ----. .-.-.- --..-- ---... ..--.. .----. -....- -..-. .--.-. -...- .-..-. -.-.--";
    // Aquí define tu mensaje separado por espacios
    char mensaje[LONGITUD_MENSAJE];
    printf("Mensaje Morse a decodificar:\n");
    fgets(mensaje, LONGITUD_MENSAJE, stdin);
    mensaje[strcspn(mensaje, "\r\n")] = 0; // Remover salto de línea
    char delimitador[] = " ";
    // Separamos la cadena por espacios. Más información sobre strtok en https://parzibyte.me/blog/2018/11/13/separar-cadena-delimitadores-c-strtok/
    char *token = strtok(mensaje, delimitador);
    if (token != NULL) {
        while (token != NULL) {
            // Obtener cuál índice tiene este código
            int indice = buscarIndiceDeMorse(token);
            // Aquí puedes hacer lo que gustes con el ascii, yo simplemente lo imprimo
            char *ascii = simbolosAscii[indice];
            printf("%s", ascii);
            token = strtok(NULL, delimitador);
        }
    }
}

int main() {
    demostrarCodificacionMorse();
    printf("\n");
    demostrarDecodificacionMorse();
    return 0;
}

En mi caso lo he probado así:

Usando traductor de código Morse en C
Ejemplo de salida de código Morse a ASCII y viceversa en C

 

Conclusiones y notas

Recuerda que uso fgets porque es más seguro que scanf. Si quieres que esto funcione con cadenas más largas simplemente cambia el límite en LONGITUD_MENSAJE.

Por cierto, no estoy manejando el caso de que la función para buscar índices regrese -1; si quieres hacer el algoritmo más a prueba de errores simplemente haz esa comprobación.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *