알파벳으로 메시지 인코딩-후속 조치

Nov 17 2020

이 코드는 조언을 요청한 수정 된 버전의 구현입니다. 원래 질문은 여기에 있습니다 : 알파벳으로 메시지 인코딩

#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));

}

답변

2 chux-ReinstateMonica Nov 18 2020 at 01:18

선명도 테스트

with와 같은 샘플 my_decode(512)은 문자로 인코딩되는 방법 을 분석 할 가치가 있습니다.

예상 출력을 주석으로 추가하거나 테스트에 통합하십시오.

입력과 출력을 게시하는 것이 유용합니다.

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

체재

다른 코드와 아래 힌트 OP는 break들여 쓰기가 아닌 자동 포맷터를 사용 하지 않습니다. 1) 자동 포맷터 사용 권장 2) 선호{ }

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

매크로 대 코드

도우미 기능 고려

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

함수

my_decode(102)2이고 my_decode(1002)1입니다. 첫 번째는 2가 허용되고, 10,2와 1,02는 10,02와 1,002가 두 번째로 허용됩니다.


할 말이 많지 않습니다.

경미 : _MAX

...._MAX C에서 더 일반적입니다. INT_MAX

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

#define ALPH_MIN 1
#define ALPH_MAX 26

경미 : unsignedvs.unsigned int

둘 다 작동합니다. unsigned짧습니다.

이러한 스타일 문제와 마찬가지로 그룹의 코딩 표준에 맞게 코딩하십시오.

경미 : 혼합 유형

일부 코딩 표준은 unsigned % int.

사용할 수 input % 100u대를 input % 100.

2 RolandIllig Nov 18 2020 at 06:32

#include줄과 매크로 정의 사이에 빈 줄이 있어야합니다 . 물론이 줄은 모두로 시작 #하므로 비슷해 보이지만 목적은 완전히 다릅니다. 따라서 이러한 각 그룹은 자체 단락을 가져야합니다.

#include <stdio.h>

#define MIN_ALPH 1
#define MAX_ALPH 26

프로그램 만의 기능을 사용하기 때문에 stdio.h, 당신은 포함 할 필요가 없습니다 stdlib.h. 그래서 위의 코드에서 생략했습니다.

이제 코드의 흥미로운 부분 인 함수 my_decode. 이 함수는 possible_encodings실제로 함수가하는 일과 더 잘 일치하므로 오히려 호출되어야합니다 . 이 제안은 이미 원래 질문의 리뷰에 표시되었으므로 후속 검토 요청에서 원본 리뷰에 대한 텍스트, 마음에 들었던 부분, 싫어하는 부분, 왜 그런지 작성해야합니다. 당신이 한 방식으로 코드를 작성했습니다. 당신은이 모든 것을하지 않았습니다.

함수 my_decode는 인수를 문자열로 가져야합니다. 이렇게하면 9 자리 또는 10 자리 숫자가 아닌 큰 숫자 시퀀스로 쉽게 테스트 할 수 있습니다. 이것은 파이썬이 아닌 C이기 때문에, 데이터 유형 int이 표현할 수있는 숫자가 상당히 제한적입니다. 일반적으로 -2147483648에서 2147483647까지입니다.

이 기능 my_decode은 완전히 문서화되지 않았습니다. 각 함수에는 그 목적을 설명하는 한 줄 이상의 주석이 있어야합니다. 대신에 정말 좋은 댓글이 main있지만 그 댓글은 거기에 속하지 않습니다. 함수 바로 위에 속합니다 my_decode.

에서는 my_decode매크로가 필요하지 않습니다. 매크로를 사용하지 말고 static대신 함수를 사용하십시오. 매크로는 텍스트 대체 용이고 함수는 계산 용입니다. 다음은 함수의 예입니다.

#include <stdbool.h>

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

C 프로그래밍 언어에는 between연산자 가 없습니다 . 이 연산자는 위의 형식을 사용하여 근사화 할 수 있으며, 단일 종류의 비교 연산자 만 사용하여 혼동을 줄일 수 있다는 이점이 있습니다.

일반적으로 비교는로 작성되며이 subject <=> object경우의 주제는입니다 n. 이 가이드 라인을 위반 하는 경우에만 오퍼레이터 사이에 있어야합니다.

여전히에서는 코드가 3 자리 숫자로만 작동 my_decode하는 % 100것처럼 의심스러워 보입니다. 이 가정이 잘못되었음을 증명하려면 테스트 데이터에 더 긴 숫자 시퀀스에 대한 몇 가지 테스트 케이스도 포함되어야합니다.

스타일 적으로 코드는 완전히 일관성이 없어 보입니다. 때로 당신은 쓸 때도 count = 0있고, i=1어떤 때는 =. 지루하므로 직접 서식을 지정하지 마십시오. 편집기 또는 IDE가이 작업을 수행하도록하십시오. "자동 형식 코드"를 검색하면이 작업에 대한 지침을 찾을 수 있습니다.

특별한 경우 i == 1000가 잘못되었습니다. 왜이 추가 if진술을 작성 했습니까? 전체 함수 my_decode는 까다로운 코드 조각이므로 각 문을 추가 한 이유를 코드 독자에게 설명해야합니다. 이 코드를 프로그래밍 할 수 있지만 문제 설명과 코드 만 알고있는 사람에게이 코드를 설명해야한다고 상상해보십시오. 설명하고 싶은 다른 모든 내용은 댓글에 넣어야합니다.

다른 사람들이 이미 말했듯이 printf 전용 테스트를 사용하지 마십시오. 테스트가 결과를 직접 확인하도록합니다. 예를 들어,이 리뷰에서 다른 프로그래밍 언어 인 Go에서 동일한 문제를 해결하고 다음과 같은 간단한 테스트 목록을 만들었습니다.

    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},
    }

이 목록은 확장하기 쉬우므로 테스트를 작성해야합니다. 물론 C에서는 약간 다르게 보이지만 기본 규칙은 한 줄에 하나의 테스트와 필요한 추가 주석을 갖는 것입니다.

1 Noname Nov 18 2020 at 20:21

알고리즘 자체로 돌아갑니다. 나는 이것에 많은 조합이 있다고 느낍니다. 나는 한 걸음 물러서서 "순열 그룹"으로 그룹화했습니다.

입력으로 "ABC"는 다음 그룹 또는 영역을 나타냅니다.

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

"123"은 "ABC"일 수 있지만 "LC"및 "AW"일 수도 있습니다. OP.v1에서 "111"은 "AAA", "AK"또는 "KA"가 될 수 있습니다.

더 긴 그룹은 "212223"이며 여기서는 "BABBBC"로 단일화됩니다. 또한 "UVW"와 "BLBW"등이 있습니다.

#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;
}

이것은 세 가지 테스트 디코딩을 제공합니다.

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]

"J"와 "T"앞의 잘못된 괄호를 제외하고 코드가 지금 작동 할 수도 있습니다. "10"및 "20"은 실제로 먼저 필터링되어야합니다. 그렇지 않으면 2 자 미리보기가 필요합니다.