코딩,해볼까

08.17. 프로그래머스 : 신규 아이디 추천 본문

Back/TIL

08.17. 프로그래머스 : 신규 아이디 추천

떠굥 2023. 8. 17. 15:31

🔎 신규 아이디 추천

주어진 규칙에 맞춰서 ID를 추천해주는 식을 만들어라.

"""
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이 될 때까지 반복해서 끝에 붙입니다.
"""

💡 문제풀이#1

def solution(new_id):
    answer = ''
    string = 'abcdefghijklmnopqrstuvwxyz0123456789-_.'
    
    #1, 2
    for i in new_id.lower():
        if i in string:
            answer += i
    #3  
    while '..' in answer:
        answer = answer.replace('..', '.')
    
    #4
    if answer[0] == '.' and len(answer) > 1:
        answer = answer[1:]

    if answer[-1] == '.':
        answer = answer[:-1] 

    #5
    if answer == '':
        answer += 'a'
    
    #6
    if len(answer) > 15:
        answer = answer[:15]
           
    if answer[-1] == '.':
        answer = answer[:-1]
    
    #7
    while len(answer) < 3:
        answer += answer[-1]
    return answer

도트의 개수를 찾을 때, index 위치를 알아내어 연속되는 위치에 있다면 한개로 바꿔주는 식을 짜고 싶었다. index를 알아내는 것 까지는 성공했지만, 하지만 너무 복잡하고 내가 원하는 방향으로 식이 완성되지 않았다. 시간도 오래 걸려서 우선은 접어두었다.

# 3
# dot가 몇개인지, 위치를 다 알아내서 해결해보자
dot_index = []
first_dot = answer.find(".")
for i in range(first_dot, len(answer)):
    if answer[i] == ".":
        dot_index.append(i)

# 연속된 수를 찾으면 다시 배열로 [[]] 넣어주자.
# [0, 1, 2, 6, 7, 9]
# 연속된 숫자들로 모아서 [[]] 만들어주기
# for idx, i in enumerate(dot_index):
sequence_dot = []
sdot = []
for i in range(1, len(dot_index) - 1):
    sdot.append(i)
    if dot_index[i] + 1 == dot_index[i + 1]:
        sdot.append(dot_index[i + 1])
sequence_dot.append(sdot)

 

단계별로 함수를 만들어서 풀이를 진행하였다. 
문자열 슬라이싱 단계에서 자꾸 out of range 오류가 떴다.

이를 len(answer) > 1 로 해결할 수 있었다. 왜 오류가 나는지, 왜 해결이 되는지 잘 모르겠다.
완전히 이해가 되지는 않지만, if문에 빈 문자열이 접근할 수 있기 때문에 접근하는 글자의 길이가 1보다 크면 실행되어라 라는 조건을 하나 더 추가한 것으로 보인다.

"Out of range" 오류가 발생하는 이유는 코드에서 문자열 인덱스를 잘못 사용해서입니다. 코드를 살펴보면 여러 곳에서 문자열 인덱스를 사용하는데, 이 때 주의해야 할 점이 있습니다.

if answer[0] == '.'와 if answer[-1] == '.'에서 문자열이 빈 문자열일 경우에 인덱스 접근이 발생할 수 있습니다. 빈 문자열에는 인덱스 0 또는 -1이 존재하지 않기 때문에 "Index out of range" 오류가 발생할 수 있습니다.if len(answer) > 15에서 문자열의 길이가 15보다 작을 경우 인덱스 접근이 문제 없지만, 길이가 15보다 길 경우 answer[15]에서 "Index out of range" 오류가 발생할 수 있습니다.

이러한 오류를 해결하기 위해서는 해당 인덱스에 접근하기 전에 길이를 확인하거나, 조건문을 추가하여 올바른 인덱스에 접근하도록 수정해야 합니다. 예를 들어, 빈 문자열인 경우나 길이가 15 이하인 경우에는 해당 조건에 맞게 처리하고, 인덱스 접근을 피해야 합니다.

💡 문제풀이#2

본 문제를 정규식으로 풀었을 때 아래와 같은 답이 나온다.

https://wikidocs.net/4308

import re

def solution(new_id):
    st = new_id
    st = st.lower()
    st = re.sub('[^a-z0-9\-_.]', '', st)
    st = re.sub('\.+', '.', st)
    st = re.sub('^[.]|[.]$', '', st)
    st = 'a' if len(st) == 0 else st[:15]
    st = re.sub('^[.]|[.]$', '', st)
    st = st if len(st) > 2 else st + "".join([st[-1] for i in range(3-len(st))])
    return st

7단계 해설 - 1. 문자열 길이가 2 초과면 그대로 반환. 아니라면(길이가 2이하) 원하는 길이(3)를 맞추기 위해 3에서 본래길이(len(st))를 빼준 개수만큼 for문을 돌리면서 맨마지막 글자를 리스트로 넣은 후 join으로 합쳐 st에 더해줌.

for, join 말고 st + st[-1] * (3-len(st))  ==> st.ljust(3, st[-1]) 

 

💡 문제풀이#3

def solution(new_id):
    answer = ''
    # 1
    new_id = new_id.lower()
    # 2
    for c in new_id:
        if c.isalpha() or c.isdigit() or c in ['-', '_', '.']:
            answer += c
    # 3
    while '..' in answer:
        answer = answer.replace('..', '.')
    # 4
    if answer[0] == '.':
        answer = answer[1:] if len(answer) > 1 else '.'
    if answer[-1] == '.':
        answer = answer[:-1]
    # 5
    if answer == '':
        answer = 'a'
    # 6
    if len(answer) > 15:
        answer = answer[:15]
        if answer[-1] == '.':
            answer = answer[:-1]
    # 7
    while len(answer) < 3:
        answer += answer[-1]
    return answer

내가 string = 으로 지정했던 것을 이 식에서는 isalpha(), isdigit(), ['-', '_', '.'] 으로 걸러주고 있었다.

#4에서 if문을 또 쓰는 이유 : #4에서 문자열이 '.'인 경우 즉, len(answer) = 1인 경우 슬라이싱에서 오류가 발생하기 때문입니다! 뒷 코드에서 마지막에 오는 '.'을 제거할 때 제거하겠다는거죠

Comments