본문 바로가기
개발/SWEA (D2) 문제 풀이

SW Expert Academy - 1928. Base64 Decoder(D2)

by v너굴이v 2022. 11. 12.

출처 - https://swexpertacademy.com/main/code/problem/problemDetail.do?problemLevel=2&contestProbId=AV5PR4DKAG0DFAUq&categoryId=AV5PR4DKAG0DFAUq&categoryType=CODE&problemTitle=&orderBy=FIRST_REG_DATETIME&selectCodeLang=ALL&select-1=2&pageSize=10&pageIndex=3

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

<나의 풀이>

문제를 보자마자 짜증이 난다.

MSB 오랜만이다.

단순하게 생각하면 가장 왼쪽에 있는 비트라고 생각하면 될듯하다.

주어진 문제에서는 총 24bit짜리 버퍼에 왼쪽부터 한 byte씩 총 3byte의 문자를 넣는다고 한다.

1 byte = 8bit

이후 MSB부터 6bit씩 잘라서 그 값을 읽고, 주어진 표에 따라서 Encoding 한다.

즉 주어지는 입력값을 암호라고 생각하고 이를 해독한다고 생각하면 이해하기 쉬워 보인다.

빠르게 입력값을 세팅해보자.

T = int(input())
for i in range(1,T+1):
    S = input()

정상적으로 S에 문자열이 설정되었다.

이제 이를 디코딩해야 한다.

예를 들어서 T의 경우 표를 참고하면 19이다.

이는 표의 19번째 인덱스라는 것을 알 수 있다. (표를 리스트라고 가정한다면)

이 19를 2진법으로 표기하면 010011이다.

6자리로 표기한 이유는 6bit씩 자르고 이를 encoding 한 것이 T이기 때문이다.

따라서 이 모든 입력 문자열을 2진법으로 바꿔줘야 한다.

 

그리고 중요한 것은 처음 문자를 넣을 때 24bit에 3byte씩 문자를 넣는다고 했다.

이는 다시 말하면 3글자를 넣는데 24비트 -> 한 글자당 8 비트라는 것이다.

그런데 우리는 입력값을 표에 따라 2진법을 바꿨을 때 6자리(비트)로 바꿨던 것을 기억해야 한다.

 

진짜 결론은 입력값을 이진법으로 바꾼 수에서

MSB부터 8자리씩 자르고,

이를 10진법으로 표기한 후에

그 수를 아스키코드표를 보고 대입하면 해당하는 문자가 나오는 것이다.

 

라이브러리를 사용하지 않고 풀 수 있는지는 의문이지만, 아스키코드는 사용해야 한다는 것과

문법적인 방법을 통해 이진법 및 십진법 표기를 해낼 수 있어야 하는 문제이다.

 

다시 문제로 돌아와서 입력된 값의 문자 하나하나를 이진법으로 바꾸기 위해서는 표-1을 활용해야 한다.

따라서 우리는 표-1에 해당하는 리스트를 만들어줘야 한다.

sample = ['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','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','+','/']

아까 말한 것처럼 T를 입력받는다면 sample 리스트 19번째 인덱스, 즉 19를 이진법으로 표기하면 된다.

 그렇다면 이진법으로 변환하는 코드를 작성해야 한다.

주의할 점은 6자리로 표기해야 하는 것이다.

입력 문자열의 글자 수만큼 반복문을 실행해야 하므로 len()을 사용하면 좋겠다.

for j in range(len(S)):
   number = sample.index(S[j])

글자를 표를 보고 바꾼 수를 number라고 하면, 이는 sample이라는 리스트에서 입력받은 S의 문자 하나랑 같은 것을 찾으면 된다.

그래서 index()를 사용하여 해당 인덱스 번호를 찾아온다. (이는 곧 문자의 숫자)

이 number를 2진법으로 표기하면 되는 것이다.

bit_num = str(bin(number))

파이썬에서 제공해주는 bin() 함수를 사용하면 간단하게 이진법으로 표기할 수 있다.

그런데 주의할 점은 앞에 2글자는 몇 진법인지를 표기해주기 때문에, 우리가 필요한 것은 2번째 자리부터이다.

따라서 문자열을 슬라이싱할 필요가 있다.

bit_num = str(bin(number)[2:])

그런데 예시 '19'처럼 5자리만 표기가 되는 것이 아니라 6자리로 표기하기 위해 앞자리에 0을 표기해주는 것이 필요하다.

이는 파이썬에서 제공하는 zfill()을 사용하면 된다.

bit_number = bit_num.zfill(6)

6자리를 기준으로 빈칸이 존재할 경우 앞에서부터 0을 채워준다.

이렇게 하면 입력 문자열의 한 글자를 바꾼 것이다.

따라서 모든 글자마다 이 과정을 반복해야 하고, 각 결과를 하나의 문자로 이어 줄 필요가 있다.

그래서 새로운 문자열 text_number을 선언하고 이에 순차적으로 저장을 해두자.

T = int(input())
for i in range(1,T+1):
    S = input()
    text_number = ''
    for j in range(len(S)): 
        number = sample.index(S[j])
        bit_num = str(bin(number)[2:])
        text = bit_num.zfill(6)
        text_number += text
 010011000110100101100110011001010010000001101001011101000111001101100101011011000110011000100000011010010111001100100000011000010010000001110001011101010110111101110100011000010111010001101001011011110110111000101110

대략 이런 식으로 잘 저장되는 것을 확인했다.

이제 이 이진법으로 된 수를 8자리씩 자른 후 아스키코드로 해독을 하면 된다.

총길이를 확인하고 이를 8자리씩 자르는 과정이 필요하다.

for k in range(len(text_number)//8):

이렇게 시도를 해봤는데 에러가 발생했다.

다른 방법을 생각해보았는데, 주어지는 S의 길이에 6을 곱하고 8을 나누면 같은 값이 나올 것이라 생각해서 바꿔보았다.

T = int(input())
for i in range(1,T+1):
    S = input()
    t
ext_number = ''
    for j in range(len(S)): 
        number = sample.index(S[j])
        bit_num = str(bin(number)[2:])
        text = bit_num.zfill(6)
        text_number += text
    
    for k in range(len(S)*6//8):

이후 0번째부터 8자리를 자르는 과정을 진행해야 한다.

text_number[0:8],text_number[8:16],...

이를 반복문과 연관 지어 작성해보면 다음과 같다.

 for k in range(len(S)*6//8):
    text_number[k*8:k*8+8]

이때 text_number[k*8:k*8+8]는 이진법으로 표기된 수이다.

이를 10진법으로 표기하려면 다음을 활용하면 된다.

int('2진법 수', 2) / int('8진법 수', 8) / int('16진법 수', 16)
for k in range(len(S)*6//8):
    value = int(text_number[k*8:k*8+8],2)

마지막으로 10진법 수를 아스키코드 변환을 통해 바꿔주는 함수 chr()을 사용하자.

result = ''
for k in range(len(S)*6//8):
    value = int(text_number[k*8:k*8+8],2)
    result += chr(value)

최종 코드를 작성하면 다음과 같다.

sample = ['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','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','+','/']

T = int(input())
for i in range(1,T+1):
    S = input()
    text_number = ''
    for j in range(len(S)):
        number = sample.index(S[j])
        bit_num = str(bin(number)[2:])
        text = bit_num.zfill(6)
        text_number += text

    result = ''
    for s in range(len(S)*6//8):
        value = int(text_number[s*8 : s*8+8],2)
        result += chr(value)
        print('#{} {}'.format(i,result))

정말 많은 개념이 담겼던 문제였다.

풀고 나서 힘이 빠지는 듯했으나 배운 것들을 잘 활용할 수 있도록 복습도 해야겠다.

댓글