문제
문제 : https://school.programmers.co.kr/learn/courses/30/lessons/72410
카카오에 입사해 카카오계정개발팀에 배치된 신입 개발자 네오는 카카오 서비스에 가입하는 사용자의 아이디를 생성하는 업무를 담당하게 되었다. 네오에게 주어진 업무는 새로 가입하는 사용자가 규칙에 맞지 않는 아이디를 입력하면 입력한 아이디와 유사하면서 규칙에 맞는 아이디를 추천해 주는 것이다.
아이디 규칙은 다음과 같다.
- 아이디의 길이는 3자 이상 15자 이하여야 한다.
- 아이디는 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.) 문자만 사용할 수 있다.
- 단, 마침표(.)는 처음과 끝에 사용할 수 없으며 또한 연속으로 사용할 수 없다.
네오는 다음과 같은 처리를 순차적으로 적용하여 사용자가 입력한 아이디가 규칙에 맞는지 검사하고 규칙에 맞는 아이디를 추천하고자 한다.
1단계 new_id의 모든 대문자를 대응되는 소문자로 치환한다.
2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거한다.
3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환한다.
4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거한다.
5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입한다.
6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거한다. 만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거한다.
7단계 new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 붙인다.
추천 아이디를 반환하는 프로그램을 작성해본다.
내 풀이
문제에 작성된 처리 과정 그대로 작성하면 된다. 작성할 때 주의했던 부분만 따로 적는다.
2단계
정규식 패턴을 이용해 허용하는 문자를 선언한 뒤, 일치하는 문자열을 모두 찾아 join 했다.
allow_str = '[a-z]|[0-9]|-|_|\.'
new_id = ''.join(re.findall(allow_str, new_id))
3, 4단계
마침표를 제거하는 부분은 제거할 부분을 찾을 수 없을 때까지 반복해야 한다.
while '..' in new_id:
new_id = new_id.replace('..', '.')
while re.search('^\.', new_id):
new_id = new_id[1:]
while re.search('\.$', new_id):
new_id = new_id[:-1]
전체 코드는 접은글로 대체한다.
import re
def solution(new_id):
allow_str = '[a-z]|[0-9]|-|_|\.'
max_len = 16
min_len = 3
# step - 1
new_id = new_id.lower()
# step - 2
new_id = ''.join(re.findall(allow_str, new_id))
# step - 3
while '..' in new_id:
new_id = new_id.replace('..', '.')
# step - 4
while re.search('^\.', new_id):
new_id = new_id[1:]
while re.search('\.$', new_id):
new_id = new_id[:-1]
# step - 5
if not new_id:
new_id = 'a'
# step - 6
if len(new_id) >= max_len:
new_id = new_id[:max_len - 1]
while re.search('\.$', new_id):
new_id = new_id[:-1]
# step - 7
if len(new_id) < min_len:
new_id += new_id[-1] * min_len
new_id = new_id[:min_len]
return new_id
다른 풀이
정규식을 좀 더 적극적으로 사용하면 보다 간결하고 좋은 성능의 코드를 작성할 수 있다.
정규식 패턴에 대한 문자열 치환은 2022.08.31 - [정규 표현식] sub - 문자열 치환을 참고한다.
2단계
정규식 패턴을 이용해 허용하는 문자와 일치하는 않는 문자는 공백으로 대체한다.
new_id = re.sub('[^a-z0-9\-_\.]', '', new_id)
3, 4단계
마침표가 하나 이상 연속적으로 일치하는 경우, 마침표로 치환하면 반복적으로 치환하지 않을 수 있다. 즉, 여러 개의 마침표가 연속적으로 나타나는 경우 모두 하나의 마침표로 치환한다.
3단계에서 연속적인 마침표를 모두 제거했으므로 4단계는 한 번만 수행해도 된다.
new_id = re.sub('\.+', '.', new_id)
new_id = re.sub('^\.|\.$', '', new_id)
5, 6단계
문자열이 비어있으면 'a'로 초기화하고 비어있지 않으면 15자까지로 자른다. 자른 부분이 마침표로 끝나면 마침표를 제거한다.
new_id = new_id[:max_len] if new_id else 'a'
new_id = re.sub('\.$', '', new_id)
7단계
문자열이 특정 길이보다 짧으면 마지막 문자를 길이의 차이만큼 덧붙인다.
if len(new_id) < min_len:
new_id += new_id[-1] * (min_len - len(new_id))
전체 코드는 접은글로 대체한다.
import re
def solution(new_id):
max_len = 15
min_len = 3
new_id = new_id.lower()
new_id = re.sub('[^a-z0-9\-_\.]', '', new_id)
new_id = re.sub('\.+', '.', new_id)
new_id = re.sub('^\.|\.$', '', new_id)
new_id = new_id[:max_len] if new_id else 'a'
new_id = re.sub('\.$', '', new_id)
if len(new_id) < min_len:
new_id += new_id[-1] * (min_len - len(new_id))
return new_id
참고 문서
https://school.programmers.co.kr/learn/courses/30/lessons/72410