Encoder le message par alphabets - Suivi

Nov 17 2020

Ce code est une version révisée de l'implémentation qui a demandé un avis. La question originale est ici: Encoder le message par alphabets

#include <stdio.h>
#include <stdlib.h>
#define MIN_ALPH 1
#define MAX_ALPH 26

unsigned int my_decode(unsigned int input)
{
    unsigned int count = 0;
    unsigned int ddigit;
    int i;

    //check double digit decoding
    //TODO: make macro for (num >= MIN_ALPH && num <= MAX_ALPH)
    if (input % 100 >= MIN_ALPH && input % 100 <= MAX_ALPH)
        count++;

    if (input / 10 >= MIN_ALPH && input / 10 <= MAX_ALPH)
    {
        if (input % 10 > 0)
            count++;
    }

    //check single digit decoding
    for (i=1; i <= 100; i*=10)
    {
        if (input % (i *10) / i == 0)
        break;
    }
    if (i == 1000)
        count++;

    return count;
}

int main(void)
{
    /*Given the mapping a = 1, b = 2, ... z = 26, and an encoded message,
    count the number of ways it can be decoded.
    For example, the message '111' would give 3,
    since it could be decoded as 'aaa', 'ka', and 'ak'.
    You can assume that the messages are decodable.
    For example, '001' is not allowed.*/

    printf("result: %u\n", my_decode(512));
    printf("result: %u\n", my_decode(542));
    printf("result: %u\n", my_decode(112));

}

Réponses

2 chux-ReinstateMonica Nov 18 2020 at 01:18

Tester la clarté

Un échantillon tel que avec my_decode(512)mérite une description de la façon dont, en tant que lettres, il peut être encodé.

Ajoutez en commentaire, ou intégrez en test, les sorties attendues.

L'affichage d'entrée ainsi que de sortie est utile.

printf("%u --> result: %u\n", 512, my_decode(512));

Format

Autres codes et conseils ci-dessous OP n'utilise pas de formateur automatique car il breakn'est pas en retrait. 1) Recommander d'utiliser un formateur automatique 2) Préférez{ }

    if (input % (i *10) / i == 0)
    break;
    // vs.
    if (input % (i *10) / i == 0) {
        break;
    }

Macro vs code

Considérez une fonction d'assistance

bool alph_in_range(unsigned num) {
  return num >= MIN_ALPH && num <= MAX_ALPH;
}

Fonction

my_decode(102)est 2 et my_decode(1002)est 1. Je m'attendrais à 2 pour le premier est autorisé, 10,2 et 1,02 puis 10,02 et 1,002 autorisé pour le 2ème.


Pas grand chose à dire.

Mineur: _MAX

...._MAX plus courant en C comme INT_MAX

// #define MIN_ALPH 1
// #define MAX_ALPH 26

#define ALPH_MIN 1
#define ALPH_MAX 26

Mineur: unsignedvs.unsigned int

L'un ou l'autre fonctionne. unsignedest plus court.

Comme pour de tels problèmes de style, codez selon la norme de codage de votre groupe.

Mineur: types mixtes

Certaines normes de codage n'aiment pas unsigned % int.

Pourrait utiliser input % 100uvs input % 100..

2 RolandIllig Nov 18 2020 at 06:32

Il doit y avoir une ligne vide entre les #includelignes et les définitions de macro. Bien sûr, ces lignes commencent toutes par #, ce qui les rend similaires, mais leur objectif est complètement différent. Par conséquent, chacun de ces groupes devrait avoir son propre paragraphe.

#include <stdio.h>

#define MIN_ALPH 1
#define MAX_ALPH 26

Puisque votre programme n'utilise que les fonctionnalités de stdio.h, vous n'avez pas besoin d'inclure stdlib.h. C'est pourquoi je l'ai omis du code ci-dessus.

Passons maintenant à la partie intéressante de votre code, la fonction my_decode. Cette fonction devrait plutôt être appelée possible_encodingscar cela correspond mieux à ce que fait réellement la fonction. Cette suggestion est déjà apparue dans un examen de la question initiale, par conséquent, dans une demande de révision de suivi, vous devriez au moins écrire un texte sur les avis originaux, ce que vous avez aimé et ce que vous n'avez pas aimé, et pourquoi vous a écrit votre code comme vous l'avez fait. Vous n'avez rien fait de tout cela.

La fonction my_decodedoit prendre son argument comme une chaîne de caractères. De cette façon, il sera facile de le tester avec de grandes séquences de chiffres, pas seulement 9 ou 10 chiffres. Comme il s'agit de C et non de Python, le type de données intest assez limité dans les nombres qu'il peut représenter. Il s'agit généralement de -2147483648 à 2147483647.

La fonction my_decodeest complètement non documentée. Chaque fonction doit avoir au moins un commentaire d'une seule ligne qui décrit son objectif. Au lieu de cela, vous avez un très bon commentaire main, mais ce commentaire n'a pas sa place. Il appartient juste au-dessus de la fonction my_decode.

Dans my_decode, il n'y a pas besoin de macro. N'utilisez pas de macros, utilisez staticplutôt des fonctions. Les macros sont destinées au remplacement textuel, les fonctions sont destinées au calcul. Voici un exemple de fonction:

#include <stdbool.h>

static bool is_in_range(int n)
{
    return MIN_ALPH <= n && n <= MAX_ALPH;
}

Le langage de programmation C n'a pas d' betweenopérateur. Cet opérateur peut être approché à l'aide du formulaire ci-dessus, qui présente l'avantage de n'utiliser qu'un seul type d'opérateur de comparaison, réduisant ainsi toute confusion.

Habituellement, les comparaisons sont écrites comme subject <=> object, et le sujet dans ce cas serait n. Ce n'est que dans le cas de l' opérateur entre que cette directive doit être violée.

Toujours là my_decode, cela % 100semble suspect, comme si votre code ne fonctionnerait que pour les nombres à 3 chiffres. Pour prouver que cette hypothèse est erronée, vos données de test doivent également inclure quelques cas de test pour des séquences de chiffres plus longues.

Stylistiquement, votre code semble complètement incohérent. Parfois vous écrivez count = 0, d'autres fois vous écrivez i=1sans espace autour du =. Ne faites pas ce formatage vous-même, car c'est ennuyeux. Laissez votre éditeur ou votre IDE faire ce travail pour vous. Recherchez «code de formatage automatique» et vous trouverez des instructions pour le faire.

Le cas particulier i == 1000est faux. Pourquoi avez-vous même écrit cette ifdéclaration supplémentaire ? Puisque la fonction entière my_decodeest un petit morceau de code délicat, vous devriez expliquer au lecteur du code pourquoi vous avez ajouté chaque instruction. Imaginez que vous deviez expliquer ce code à quelqu'un qui peut programmer mais qui ne connaît que la description du problème et le code. Tout ce que vous voulez expliquer doit être placé dans les commentaires.

Comme d'autres l'ont déjà dit, n'utilisez pas de tests uniquement printf. Faites en sorte que les tests vérifient eux-mêmes leurs résultats. Par exemple, au cours de cet examen, j'ai résolu le même problème dans Go, un autre langage de programmation, et j'ai élaboré cette simple liste de tests:

    tests := []struct {
        input string
        want  uint64
    }{
        {"", 1},
        {"1", 1},
        {"11", 2},
        {"111", 3},
        {"1111", 5},
        {"11111", 8},
        {"10", 1},
        {"201", 1},
        {"11111011111", 40}, // == 5 * 8
        {"1000", 0},
    }

Cette liste est facile à étendre et c'est ainsi que vous devez rédiger vos tests. Bien sûr, en C, cela semble un peu différent, mais la règle de base est d'avoir un test par ligne, plus les commentaires supplémentaires nécessaires.

1 Noname Nov 18 2020 at 20:21

Je reviens à l'algorithme lui-même. Je pense qu'il y a beaucoup de combinatoire là-dedans. J'ai pris du recul et j'ai fait le regroupement en "groupes de permutation".

Le "ABC" comme entrée illustre ces groupes ou régions:

$ ./a.out
1234567891011121314151617181920212223242526 [Code]
(ABC)DEFGHIJ(AAABAC)(AD)(AE)(AF)(AG)(AH)(AI)T(BABBBC)(BD)(BE)(BF) [Decoded: single, grouped] 

"123" peut être "ABC", mais aussi "LC" et "AW". Tout comme "111" peut être "AAA", "AK" ou "KA" dans OP.v1.

Un groupe plus long est "212223", qui est ici singlé en "BABBBC". C'est aussi "UVW", plus "BLBW", et bien d'autres.

#include <stdio.h>

void parse_msg(char *msg) {

    char c, cprev, cnext;
    int i;
    /* Start in a state like after a high digit 3..9 */
    cprev = '9';
    for (i = 0; msg[i] != '\0'; i++) {
    
        c     = msg[i];
        cnext = msg[i+1];

        /* "10" and "20" are special cases, get rid of them */ 
        if (cnext == '0') {
            if (cprev <= '2')
                printf(")");    
            if (c == '1')
                printf("J");    
            if (c == '2')
                printf("T");    
            if (c >= '3') {
                printf("******* Error: zero 30-90\n");
                return;         
            }
            cprev = '9'; // reset 
            i++;         // extra skip in msg
            continue;
        }
        /* 1: No matter what cnext is (1-9), open a "(" group */
        /*    But don't open if next is the null byte */ 
        /*    Problem: makes "(" even if "10" follows */
        if (c == '1') {
            if (cprev >= '3') 
                if (cnext == '\0') 
                    cprev = '9';        
                else {
                    printf("(");        
                    cprev = c;          
                }
            printf("A");
            continue;
        }

        /* 2: Open before or close after */
        if (c == '2') {
            /* new group only if 321-326 */
            if (cprev >= '3' && cnext <= '6')
                if (cnext == '\0') {
                    cprev = '9';        
                    printf("B");        
                    continue;
                }
                else
                    printf("(");        

            /* "2" is "B" in any case */    
            printf("B");

            /* "127", "229": was open, must close */ 
            if (cprev <= '2' && cnext >= '7') {
                printf(")");    
                cprev = '9';    
                continue;
            }
            cprev = c;
            continue;
        }
                 
        /* c == 3 or higher are left */

        /* if open, then close group ")" after printing */
        if (cprev == '1' ||  
            c <= '6' &&  cprev == '2') {

            printf("%c", c + 0x10);
            printf(")");
            cprev = c;  
            continue;   
        }

        printf("%c", c + 0x10);
        cprev = c;
    }

    /* Finish: maybe group is opened */ 
    if (cprev <= '2')
        printf(")");
    printf(" [Decoded: single, grouped] \n");   
    return;
}

int main(void) {
        
    char *msg = "1234567891011121314151617181920212223242526";
    printf("%s [Code]\n", msg);
    parse_msg(msg);

    msg = "2102102";
    printf("\n%s [Code]\n", msg);
    parse_msg(msg);

    msg = "1181";
    printf("\n%s [Code]\n", msg);
    parse_msg(msg);

    return 0;
}

Cela donne trois décodages de test:

1234567891011121314151617181920212223242526 [Code]
(ABC)DEFGHIJ(AAABAC)(AD)(AE)(AF)(AG)(AH)(AI)T(BABBBC)(BD)(BE)(BF) [Decoded: single, grouped] 

2102102 [Code]
(B)J(B)JB [Decoded: single, grouped] 

1181 [Code]
(AAH)A [Decoded: single, grouped]

Peut-être que le code fonctionne maintenant, sauf pour les mauvaises parenthèses devant "J" et "T". Les "10" et "20 doivent vraiment être filtrés en premier, sinon vous avez besoin d'une anticipation à 2 caractères.