Search code examples
ctaskmorse-codec-standard-library

Findnig 3 spaces during Morse code decoding


I was solving just simple task for learning purposes. Task: Encode the given string with morse code, return the encoded string. Problem: 3 spaces denoting 1 space between words in morse code are lost when the string is split into tokens.

The result should be: "HEY JUDE" Current result: "H EYJ U D E"

During the solution my approach changed 3 times

  • i was iterating all the symbols from original msg and vocabulary one by one
  • i was building a state machine with like 7 states And finally i found the best approach from my point of view
  • Splitting the giving string into the tokens and then compare with strcmp with the vocabulary

But the problem is that during the splitting with strtok i am missing the 3 spaces which should be exactly the "pointer" to where exactly should i put the spaces during the encoding procedure. I came out with the solution of that thing - check out the find_space_positions functions. But its working not completely correct and i don't understand why.

Could please help me to understand why the find_space_positions is not working the way it supposed to be? How to make it work the way i want to ?

What is the better approach to do such stuff in C ?

Here is the code:


#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include<stdio.h>


const char *morse[55] = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", "-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----.", ".-.-.-", "--..--", "..--..", ".----.", "-.-.--", "-..-.", "-.--.", "-.--.-", ".-...", "---...", "-.-.-.", "-...-", ".-.-.", "-....-", "..--.-", ".-..-.", "...-..-", ".--.-.", "...---..."};
const char *ascii[55] = {"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",     ".",      ",",      "?",      "'",      "!",      "/",     "(",     ")",      "&",     ":",      ";",      "=",     "+",     "-",      "_",      "\"",     "$",       "@",      "SOS"};

char input[] = ".... . -.--   .--- ..- -.. .";

static uint16_t msg_iter = 0;
static uint16_t voc_word_iter = 0;
static uint16_t voc_word_chr_iter = 0;
static uint16_t iter = 0;
static char buf[20] = "";

bool find_space_positions (const char* morse_code, uint16_t token_counter, uint16_t len ) {
    uint16_t space_counter = 0;
    for (uint16_t i = 0; i <len; i++){
        printf("%c\n", morse_code[i]);
        if (morse_code[i] == ' ') {
            space_counter++;
            printf("%d+++ \n", space_counter);
        }
        else if (space_counter == token_counter) {
            if (morse_code[i + 1] == ' ' && morse_code[i + 2] == ' ') {
                return true;
            }
            else {
                return false;
            }

        }
    }


}

void decode_morse(const char *morse_code) {
    uint16_t input_len = strlen(morse_code);
    char *word = strtok(morse_code, " ");
    uint16_t token_number = 1;

    while (word != NULL) {
        for (int voc_word_iter = 0; voc_word_iter < 55; voc_word_iter++) {
            if (strcmp(word, morse[voc_word_iter]) == 0) {
                if (find_space_positions(input,token_number, input_len )) {
                    buf[iter] = ' ';
                    iter++;
                }
                buf[iter] = *ascii[voc_word_iter];
                iter++;
                break;
            }
        }

        word = strtok(NULL, " ");
        token_number++;
        }


    printf("%s\n", buf);
}




int main () {
    decode_morse(input);
    return 777;
}


". ." v


Solution

  • "But its working not completely correct and i don't understand why."

    It's difficult to diagnose optimistic code that is doing the wrong thing in the wrong way. However, it's worth noting that the helper function find_space_positions() tries hard to find the smoking remains of what once was 3 consecutive spaces. Unfortunately, this helper function is counting the remaining pair of SP's as 2 when it searching for token_num that is only 1 (for each word...). It's all a bit too wrong to correct.

    As directed by "What is the better approach to do such stuff in C ?" the following is offered as implementing the approach outlined in the comments:

    // Your #includes and arrays of morse[] & ascii not repeated here
    
    char decode_morse_char( char *cp ) {
        // Find a match in the array of Morse strings
        // Return the single ASCII character (or '#' for not found)
        for( int i = 0; i < sizeof morse / sizeof morse[0]; i++ )
            if( strcmp( cp, morse[i] ) == 0 )
                return ascii[i][0];
        return '#'; // not in alphabet, 
    }
    
    void decode_morse_word( char *cp ) {
        // break the "word" into individual Morse strings for lookup
        for( char *ltr = cp; (ltr = strtok( ltr, " " ) ) != NULL; ltr = NULL )
            putchar( decode_morse_char( ltr ) ); // decode one Morse character code
    }
    
    void decode_morse_text( char *cp ) {
        char *wordSep = "   "; // break into "words" on 3 SP's together
        char *ep;
        while( ( ep = strstr( cp, wordSep ) ) != NULL ) {
            *ep = '\0'; // "tokenise" the word in the buffer
            decode_morse_word( cp ); // decode one "word"
            putchar( ' ' ); // and output a separating SP
            cp = ep + 1;
        }
        decode_morse_word( cp ); // the final "word"
        putchar( '\n' );
    }
    
    int main( void ) {
        char input[] = ".... . -.--   .--- ..- -.. .";
    
        decode_morse_text( input ); // entire string
    
        return 0;
    }
    

    Note that each function does one thing. The hierarchy approach follows the KISS principle.

    This does output "HEY JUDE".

    - .- -.- . .- ... .- -.. -.-. --- -.. . .- -. -.. -- .- -.- . .. - -... . - - . .-.

    EDIT:
    As a bonus, here is your morse[] and ascii[] arrays merged into a single array. Using this, all that is needed is to alter the strcmp() in the function/loop that is searching for a match:

    char *morse[] = {
        "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----.",
        "..-.-.-",  ",--..--",  "?..--..",  "'.----.",  "!-.-.--",
        "/-..-.",   "(-.--.",   ")-.--.-",  "&.-...",   ":---...",
        ";-.-.-.",  "=-...-",   "+.-.-.",   "--....-",  "_..--.-",
        "\\.-..-.",  "$...-..-", "@.--.-.",
    };
    
    if( strcmp( cp, morse[i] + 1) == 0 ) // +1 to ignore single prefix character
        return morse[i][0]; // return that prefix character
    

    (Needless to say, the correctness or completeness of the codes you provided have not been double-checked. Caveat emptor!)