NIRVANA

[level 1] 시저 암호 (mod로 다시 생각해보기) 본문

Coding test(Python3)/Programmers

[level 1] 시저 암호 (mod로 다시 생각해보기)

녜잉 2023. 7. 24. 22:51

문제

어떤 문장의 각 알파벳을 일정한 거리만큼 밀어서 다른 알파벳으로 바꾸는 암호화 방식을 시저 암호라고 합니다. 예를 들어 "AB"는 1만큼 밀면 "BC"가 되고, 3만큼 밀면 "DE"가 됩니다. "z"는 1만큼 밀면 "a"가 됩니다. 문자열 s와 거리 n을 입력받아 s를 n만큼 민 암호문을 만드는 함수, solution을 완성해 보세요.

 

문제 풀이 접근법1

1) 글자 s를 리스트로 변환한 뒤, 아스키 문자로 변환한다.

2) 아스키 문자 각각에 n을 더해 준다.

2-2) 이때, 만약 문자가 ""(공백)이면 그냥 건너뛰고 다음으로 간다.

3) 다시 아스키 문자를 글자로 변환한 뒤, string으로 바꿔준다. 

 

s= "a B z"
answer = []
n=4

    
for i in s:
    if i !=" ":
        print(ord(i)+n)
        answer.append(chr(ord(i)+n))
        
    
    else:
        answer.append(" ")

s = ''.join(answer)

print(s)

이 코드의 가장 큰 문제: z, Z의 경우에는 +1을 하면 다시 a로 돌아가야 하는데 이 코드는 그렇게 하지 못한다

 

 

문제 풀이 접근법2

z와 Z의 경우에는 n을 더한 후, 26을 빼도록 수정을 해주었다. 

answer = []

for i in s:
    if i !=" ":
        if ord(i) == 90 or ord(i) == 122:
            answer.append(chr(ord(i)+n-26))
        else:
            answer.append(chr(ord(i)+n))
    
    else:
        answer.append(" ")


s = ''.join(answer)
print(s)

테스트 케이스에 넣었을 때는 다 성공이었는데 실패가 떴다. 

반례를 찾기 위해서 a부터 z까지 다 넣어서 해봤는데 wxy, WXY 부근에서 에러가 나는 것을 확인했다. 

생각해보니 w, x, y나 W, X, Y 모두 n을 더했을 때, n의 크기에 따라서 아스키 코드의 알파벳 범위(65~90, 97~122)를 넘어가기 때문이었다. 

 

문제 풀이 접근법 3

따라서 위의 코드를 z혹은 Z일 때만 26을 빼주는 것이 아닌, ord(i)+n이 90이나 122를 넘으면 26을 빼주는 것으로 수정했다. 

def solution(s, n):
    answer = []
    for i in s:
        if i !=" ":
             if ord(i)+n > 64 and ord(i)+n < 91:
                answer.append(chr(ord(i)+n))
             elif ord(i) + n > 96 and ord(i) + n < 123:
                answer.append(chr(ord(i)+n))
             else:
                answer.append(chr((ord(i)+n)-26))
    
        else:
            answer.append(" ")


    s = ''.join(answer)
    return s

 

여기서도 오류가 발생했다...아 왜지?? 하면서 알파벳 다시 다 입력해서 보니까

대문자가 소문자의 범위에 들어가는 경우가 발생했다... ㅋㅋㅋㅋㅋㅋ

 

위 코드에서 n= 16이면 대충 Q부터 소문자로 변환된다. 

 

문제 풀이 접근법 4(정답!)

if-else문에 isupper()와 islower()함수를 사용하여서 대/소문자를 구분하는 코드를 추가하였다. 

def solution(s, n):
    answer = []
    for i in s:
        if i !=" ":
             if i.isupper() and ord(i)+n > 64 and ord(i)+n < 91:
                answer.append(chr(ord(i)+n))
             elif i.islower() and ord(i) + n > 96 and ord(i) + n < 123:
                answer.append(chr(ord(i)+n))
             else:
                answer.append(chr((ord(i)+n)-26))
    
        else:
            answer.append(" ")


    s = ''.join(answer)
    return s

 


다른 분들 풀이

def caesar(s, n):
    s = list(s)
    for i in range(len(s)):
        if s[i].isupper():
            s[i]=chr((ord(s[i])-ord('A')+ n)%26+ord('A'))
        elif s[i].islower():
            s[i]=chr((ord(s[i])-ord('a')+ n)%26+ord('a'))

    return "".join(s)
    # 주어진 문장을 암호화하여 반환하세요.


# 실행을 위한 테스트코드입니다.
print('s는 "a B z", n은 4인 경우: ' + caesar("a B z", 4))

와 식 어떻게 세우신거지!!

나도 처음에 mod 26 생각은 했는데 진짜 도저히 식을 어떻게 세워야할지 모르겠어서...

규칙 나름대로 찾다가 걍 26 뺐는데...ㅋㅋㅋㅋㅋㅋㅋㅋ

하 다시 생각해봐야겠다.