문제 : https://school.programmers.co.kr/learn/courses/30/lessons/72410
난이도 : Lv.1
입력으로 받은 문자열(new_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이 될 때까지 반복해서 끝에 붙입니다.
나의 풀이
def solution(new_id):
tmp = ''
# 소문자 치환
new_id = new_id.lower()
# 불가능한 문자 제거
possible_schr = ['-', '_', '.']
for s in new_id:
if s.isalpha() or s.isdigit() or s in possible_schr:
tmp += s
new_id = tmp
tmp = ''
# 중복 '.' 제거
cnt = 0
for i in new_id:
if i == '.' and cnt == 0:
cnt += 1
tmp += i
elif i == '.':
continue
else:
cnt = 0
tmp += i
new_id = tmp
# 처음, 끝 '.' 제거
new_id = new_id[1:] if new_id.startswith('.') else new_id
new_id = new_id[:-1] if new_id.endswith('.') else new_id
# 빈 문자열 확인
new_id = 'a' if len(new_id) == 0 else new_id
# 문자열 길이 체크
if len(new_id) >= 16:
new_id = new_id[:15]
new_id = new_id[:-1] if new_id.endswith('.') else new_id
# 마지막 문자 추가
while len(new_id) <= 2:
new_id += new_id[-1]
return new_id
사실 이래도 되나 싶을 정도로 너무 대충 풀었다.. 조건만 맞으면 되지~ 라는 심정!!
풀고 나니 풀이가 넘 잼민이 같아서 다른 사람꺼 참고하면서 예쁘게 다듬어보려고 했는데... 막상 다른 사람 풀이를 보니 내 코드가 마냥 잼민이 같지는 않았다..? 단순한 사람들은 다 거기서 거기ㅎㅎㅎ
근데 가장 추천수 많은 코드를 보니 정규식 관련 함수가 있었다. (내가 제일 싫어하는 거 = 정규식)
정규식 함수를 사용하니 매우 깔끔했다.
정리해보면,
1단계. 모든 대문자를 소문자로 치환한다.
str = new_id.lower()
string.lower()
모든 문자열을 소문자로 치환하는 함수.
string.upper()
소문자로 치환하는 함수가 있으면 반대로 당연히 대문자로 치환하는 함수가 존재한다.
string.islower(), string.isupper()
모든 문자가 소문자 또는 대문자인지 검사하여 bool(True, False) 반환
2단계. 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자 제거한다.
str = re.sub('[^a-z0-9\-_.]', '', str) # 소문자,숫자,-,_,. 가 아니면 빈문자열로 치환
re.sub(정규표현식, 치환문자, target 문자열)
re는 regular expression(정규표현식)의 약자이다. 그 중 sub 메소드는 조건을 만족하는 패턴을 내가 원하는 문자로 대체한다.
이 때 주로 사용하는 표현에는
. | 줄바꿈 문자를 제외한 1글자 |
^ | 문자열의 시작 또는 not |
$ | 문자열의 끝 |
[] | 문자 집합 [^a]: a를 제외한 모든 문자 [x-z]: x-z 범위 안에 있는 문자 |
| | or |
* | 0회 이상 반복되는 패턴 |
+ | 1회 이상 반복되는 패턴 |
? | 0회 또는 1회 반복되는 패턴 |
{n} | n회 반복되는 패턴 ab{2}c: abbc |
등이 있다.
3단계. 마침표(.) 가 2번 이상 연속되면 하나로 치환한다.
str = re.sub('\.+', '.', st) # '.'(escape(\) 필요)가 1번 이상이면 '.'로 치환
4단계. 마침표(.)가 처음이나 끝에 위치하면 제거한다.
str = re.sub('^[.]|[.]$', '', str) #시작이 '.' 이거나 끝이 '.'일 때 빈칸 치환
사실 위에까지 생각하기 힘들다면, 그냥 아래 코드도 나쁘지 않은 것 같다.
str = str[1:] if str.startswith('.') else str
str = str[:-1] if str.endswith('.') else str
5단계. 빈 문자열이면 "a"를 대입한다.
new_id = 'a' if len(new_id) == 0 else new_id
6단계. 16자 이상이면 15개까지 자르고, 마지막 글자 마침표(.) 체크하여 있으면 제거한다.
new_id = new_id[:15]
new_id = new_id[:-1] if new_id.endswith('.') else new_id
(4단계처럼 정규식으로 해도 됨)
7단계. 길이가 2자 이하면 마지막 문자를 길이가 3이 될 때까지 붙인다.
while len(new_id) <= 2:
new_id += new_id[-1]
완성 코드
import re
def solution(new_id):
str = new_id
# step1
str = str.lower()
# step2
str = re.sub('[^a-z0-9\-_.]', '', str)
# step3
str = re.sub('\.+', '.', str)
# step4
str = str[1:] if str.startswith('.') else str
str = str[:-1] if str.endswith('.') else str
# step5 & 6
str = 'a' if len(str) == 0 else str[:15]
str = str[:-1] if str.endswith('.') else str
# step 7
while len(str) <= 2:
str += str[-1]
return str