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
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
"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!)