문제 설명
어떤 문장의 각 알파벳을 일정한 거리만큼 밀어서 다른 알파벳으로 바꾸는 암호화 방식을 시저 암호라고 합니다. 예를 들어 AB는 1만큼 밀면 BC가 되고, 3만큼 밀면 "DE"가 됩니다. z는 1만큼 밀면 a가 됩니다. 문자열 s와 거리 n을 입력받아 s를 n만큼 민 암호문을 만드는 함수, solution을 완성해 보세요.
제한 조건
- 공백은 아무리 밀어도 공백입니다.
- s는 알파벳 소문자, 대문자, 공백으로만 이루어져 있습니다.
- s의 길이는 8000이하입니다.
- n은 1 이상, 25이하인 자연수입니다.
입출력 예
제출 코드
def solution(s, n):
small = ','.join('abcdefghijklmnopqrstuvwxyz').split(',')
capital = ','.join('ABCDEFGHIJKLMNOPQRSTUVWXYZ').split(',')
s = ','.join(s).split(',')
for i in range(len(s)):
if s[i] in small: # 소문자일 경우
if small.index(s[i]) + n <= 25:
s[i] = small[small.index(s[i])+n]
else:
s[i] = small[small.index(s[i])+n-26]
elif s[i] in capital: # 대문자일 경우
if capital.index(s[i]) + n <= 25:
s[i] = capital[capital.index(s[i])+n]
else:
s[i] = capital[capital.index(s[i])+n-26]
else: # 공백일 경우
continue
return ''.join(s)
(1) line 2 ~ line 4
소문자의 각 문자를 하나씩 small이라는 리스트에 담고, 대문자의 각 문자를 하나씩 capital이라는 리스트에 담는다. 이후 입력값으로 받는 문자열 s 또한 각 문자를 하나씩 담는 리스트로 바꾼다.
(2) line 6
입력받은 문자열에 속한 모든 문자와 공백을 확인하기 위해 반복 횟수는 len(s)이다.
(3) line 7 ~ line 11
만약 특정 문자가 소문자라면, 리스트 'small'에서 해당 문자가 몇 번째 index에 있는지 확인한다. 그 인덱스에 n칸을 오른쪽으로 미룬 값을 return해야 하니 '해당 인덱스 + n' 을 체크한다.
'해당 인덱스 + n'이 리스트 'small'의 마지막 원소의 인덱스인 25 이하라면 list index out of range 에러가 발생하지 않기 때문에 그대로 해당 문자를 오른쪽으로 n칸 미룬 값으로 바꿔준다. 반대로 '해당 인덱스 + n'이 25를 초과하게 되면, 리스트 'small'의 처음으로 돌아간 다음 오른쪽으로 더 밀려가는 것으로 생각해야 한다. 입출력 예시 3번을 보면 더 알기 쉬운데, 'z'가 오른쪽으로 4칸 밀려났을 때 list 범위를 초과해버리기 때문에 한 칸을 이동했을 때 리스트 'small'의 처음인 a로 돌아가게끔 처리해줘야 하며, 이후 오른쪽으로 나머지 3칸을 더 이동하여 'd'가 된다.
(4) line 13 ~ line 17
위 과정과 똑같다.
(5) line 19
공백일 경우에는 아무리 밀어도 공백이라는 제한 조건이 있으므로 무시하고 continue를 해준다.
(6) line 22
입력받은 문자열 s의 각 문자를 오른쪽으로 n칸 미룬 새로운 문자열은 현재 각 문자 하나하나로 떨어져있는 리스트 형태이다. 그렇기 때문에 ''을 기준으로 합쳐준 문자열을 return해준다.
반성의 시간
맨 처음 코드를 짰을 때 굉장히 바보같은 실수를 했다. 일단 1차 제출 코드는 다음과 같다.
# 1차 제출 코드
def solution(s, n):
small = 'abcdefghijklmnopqrstuvwxyz'
capital = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
for i in range(len(s)):
if s[i] in small: # 소문자일 경우
if small.index(s[i]) + n <= 25:
s = s.replace(s[i], small[small.index(s[i])+n])
else:
s = s.replace(s[i], small[small.index(s[i])+n]-26)
elif s[i] in capital: # 대문자일 경우
if capital.index(s[i]) + n <= 25:
s = s.replace(s[i], capital[capital.index(s[i])+n])
else:
s = s.replace(s[i], capital[capital.index(s[i])+n]-26)
else: # 공백일 경우
continue
return s
기존 문자에서 n칸을 오른쪽으로 밀어낸 후 문자를 바꿔내는 과정 중에서 문자열 메서드인 replace를 썼는데 계속 해서 list index out of range가 발생했다. 이유를 몰라서 그냥 리스트로 바꿔버린 후 풀어낸 것인데, 생각해보니 문자열에서 replace('a', 'b')를 해버리면 해당 문자열에 있는 모든 'a'가 'b'로 바뀐다는 것을 깨달았다. 참으로 멍청하다.
그래서 뒤늦게라도 문자열로도 충분히 할 수 있다는 생각이 들어 코드를 짜봤다. 물론 그렇게 깨끗하지는 않은 것 같다. 하지만 중요한 것은 문자열에서 특정 문자를 바꾸고 싶다면 앞과 뒤를 잘라내고 그 사이에 새로운 문자열을 붙여야 한다는 것이다! 기본적인 것들을 자꾸 까먹어서 참 문제다.
# 1차 제출 코드를 수정한 것
def solution(s, n):
small = 'abcdefghijklmnopqrstuvwxyz'
capital = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
for i in range(len(s)):
if s[i] in small: # 소문자일 경우
if small.index(s[i]) + n <= 25:
if i != len(s)-1:
s = s[:i] + small[small.index(s[i])+n] + s[i+1:]
else:
s = s[:i] + small[small.index(s[i])+n]
else:
if i != len(s)-1:
s = s[:i] + small[small.index(s[i])+n-26] + s[i+1:]
else:
s = s[:i] + small[small.index(s[i])+n-26]
elif s[i] in capital: # 대문자일 경우
if capital.index(s[i]) + n <= 25:
if i != len(s)-1:
s = s[:i] + capital[capital.index(s[i])+n] + s[i+1:]
else:
s = s[:i] + capital[capital.index(s[i])+n]
else:
if i != len(s)-1:
s = s[:i] + capital[capital.index(s[i])+n-26] + s[i+1:]
else:
s = s[:i] + capital[capital.index(s[i])+n-26]
else: # 공백일 경우
continue
return s
Source : https://programmers.co.kr/learn/courses/30/lessons/12926
'PS > 프로그래머스' 카테고리의 다른 글
[프로그래머스][파이썬/Python] (2019 카카오 코딩테스트) 오픈채팅방 (0) | 2020.03.09 |
---|---|
[프로그래머스][파이썬/Python] 프린터 (0) | 2020.03.08 |
[프로그래머스][파이썬/Python] (2018 서머코딩/윈터코딩) 스킬트리 (0) | 2020.03.06 |
[프로그래머스][파이썬/Python] 쇠막대기 (0) | 2020.03.05 |
[프로그래머스][파이썬/Python] (2018 카카오 코딩테스트) 비밀지도 (0) | 2020.03.04 |