알파벳으로 메시지 인코딩-후속 조치
이 코드는 조언을 요청한 수정 된 버전의 구현입니다. 원래 질문은 여기에 있습니다 : 알파벳으로 메시지 인코딩
#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));
}
답변
선명도 테스트
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
경미 : unsigned
vs.unsigned int
둘 다 작동합니다. unsigned
짧습니다.
이러한 스타일 문제와 마찬가지로 그룹의 코딩 표준에 맞게 코딩하십시오.
경미 : 혼합 유형
일부 코딩 표준은 unsigned % int
.
사용할 수 input % 100u
대를 input % 100
.
#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에서는 약간 다르게 보이지만 기본 규칙은 한 줄에 하나의 테스트와 필요한 추가 주석을 갖는 것입니다.
알고리즘 자체로 돌아갑니다. 나는 이것에 많은 조합이 있다고 느낍니다. 나는 한 걸음 물러서서 "순열 그룹"으로 그룹화했습니다.
입력으로 "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 자 미리보기가 필요합니다.