99클럽 코테 스터디 4/99일차 TIL # JadenCase 문자열 만들기(미들러)
- -
문제: JadenCase 문자열 만들기
출처: 프로그래머스
https://school.programmers.co.kr/learn/courses/30/lessons/12951
1. 문제 설명
JadenCase란 모든 단어의 첫 문자가 대문자이고, 그 외의 알파벳은 소문자인 문자열입니다. 단, 첫 문자가 알파벳이 아닐 때에는 이어지는 알파벳은 소문자로 쓰면 됩니다. (첫 번째 입출력 예 참고)
문자열 s가 주어졌을 때, s를 JadenCase로 바꾼 문자열을 리턴하는 함수, solution을 완성해주세요.
2. 문제 해석
JadenCase: 첫 문자 대문자 나머지는 소문자 - 첫 문자가 알파벳이 아니면 나머지 이어지는 문자 소문자 - 공백 나오면 그 다음은 대문자로 바꾸면 된다.
3. 문제 풀이
풀이 (1) 44.4/100
1. 대소문자 isupper() / upper() / lower() 활용 2. 공백 단위로 문자열 자르기 split()
2. s for문 돌면서 조건에 따라 문자 변환
(1) 첫 문자가 숫자일 경우 나머지 소문자
(2) 첫 문자가 문자일 경우 대문자, 나머지는 소문자
(3) 해당 조건은 공백이 나오면 종료 - tmp에 넣기 - 최종 ''.join()으로 answer return
def solution(s):
words = s.split()
print(words)
nums = ['0', '1', '2', '3', '4', '5', '6', '7','8', '9']
tmp = []
for word in words:
# case_1: 숫자로 시작하는 경우 -> 숫자는 단어의 첫 문자로만 나옵니다.
# print(type(word[0]), word[0])
# <class 'str'> 3
if word[0] in nums:
print(word[1:])
to_append = word[0] + word[1:].lower()
tmp.append(to_append)
# tmp.append(word[0])
# tmp.append(word[1:].lower())
else:
to_append = word[0].upper() + word[1:].lower()
tmp.append(to_append)
# tmp.append(word[0].upper())
# tmp.append(word[1:].lower())
print(tmp)
answer = ' '.join(tmp)
return answer
기본 테스트는 통과 하였다.
하지만 테스트 케이스 절반 이상이 실패가 나왔다.
테스트 1 〉 | 통과 (0.01ms, 10MB) |
테스트 2 〉 | 실패 (0.01ms, 10.3MB) |
테스트 3 〉 | 통과 (0.01ms, 10.2MB) |
테스트 4 〉 | 실패 (0.02ms, 10.3MB) |
테스트 5 〉 | 실패 (0.04ms, 10MB) |
테스트 6 〉 | 통과 (0.02ms, 10.1MB) |
테스트 7 〉 | 통과 (0.02ms, 10.3MB) |
테스트 8 〉 | 실패 (0.01ms, 10.1MB) |
테스트 9 〉 | 실패 (0.02ms, 10.3MB) |
테스트 10 〉 | 통과 (0.01ms, 10.2MB) |
테스트 11 〉 | 실패 (0.02ms, 10.1MB) |
테스트 12 〉 | 실패 (0.02ms, 10.3MB) |
테스트 13 〉 | 실패 (0.02ms, 10.1MB) |
테스트 14 〉 | 실패 (0.02ms, 10.1MB) |
테스트 15 〉 | 통과 (0.03ms, 10MB) |
테스트 16 〉 | 통과 (0.01ms, 10.1MB) |
테스트 17 〉 | 실패 (0.03ms, 10.1MB) |
테스트 18 〉 | 통과 (0.01ms, 10.2MB) |
아무리 해당 풀이의 잘못된 점을 찾으려고 해도 전혀 찾아지지 않았다. 풀이시간이 지나서 결국 chatgpt 형님께 물었다.
그렇다. 내가 문자열을 공백을 기준으로 s.split()을 했는데 이 부분이 문제가 될 수 있었다.
그래서 split()을 쓰기 전에 공백 개수를 알고 이를 이용해서 특정 위치의 공백이 1개가 아닌 경우 문제가 생길 수 있는 풀이였던 것이다.
공백이 1개가 아닌 여러개인 경우를 고려하려면 결국 for문을 돌면서 해당 공백의 위치를 찾고, 그 공백의 개수까지 일일히 찾아야 하는 것이다.
결국은 GPT 형님이 말해주신대로 단어 단위로 자르면 공백을 또 고려를 해야하므로 문자 단위로 로직을 바꾸는 것이 맞는 풀이였다.
풀이 (2) 100/100
def solution(s):
nums = ['0', '1', '2', '3', '4', '5', '6', '7','8', '9']
tmp = []
# 문자열 확인 조건 설정
# 공백이 나올 경우 조건을 True로 설정
# True일 경우 다음에 나온 문자열을 대문자화 후 False로 변경
# 나머지 케이스에 대해서는 소문자화
capitalize = True
for char in s:
# 공백 case
if char.isspace():
tmp.append(char)
capitalize = True
# 대문자화 case, 공백 후 문자
elif capitalize:
tmp.append(char.upper())
capitalize = False
# 소문자화 case
else:
tmp.append(char.lower())
answer = ''.join(tmp)
return answer
앞의 풀이가 단어 단위로 split을 하고 갔다면 이를 char(문자) 단위로 for문을 다시 도는 방법이다.
다른점이라면 내가 대문자화 할건지 안할건지를 조건으로 설정하고 이에 따라 문자열을 대문자화/소문자화 하고 리스트에 추가한다.
이렇게 되면 오히려 로직이 훨씬 더 간단해진다!
특히 공백이 몇개이건 capitalize가 유지가 되기 때문에 공백을 걱정할 필요 없이 차례로 문자열 확인이 가능해진다.
테스트 1 〉 | 통과 (0.02ms, 10.1MB) |
테스트 2 〉 | 통과 (0.02ms, 10.2MB) |
테스트 3 〉 | 통과 (0.03ms, 10.1MB) |
테스트 4 〉 | 통과 (0.02ms, 10.1MB) |
테스트 5 〉 | 통과 (0.06ms, 10.1MB) |
테스트 6 〉 | 통과 (0.02ms, 9.96MB) |
테스트 7 〉 | 통과 (0.02ms, 10.4MB) |
테스트 8 〉 | 통과 (0.01ms, 10.2MB) |
테스트 9 〉 | 통과 (0.02ms, 10.1MB) |
테스트 10 〉 | 통과 (0.01ms, 10.2MB) |
테스트 11 〉 | 통과 (0.03ms, 10.3MB) |
테스트 12 〉 | 통과 (0.03ms, 10.1MB) |
테스트 13 〉 | 통과 (0.03ms, 10.1MB) |
테스트 14 〉 | 통과 (0.02ms, 10.2MB) |
테스트 15 〉 | 통과 (0.04ms, 10.1MB) |
테스트 16 〉 | 통과 (0.01ms, 10.3MB) |
테스트 17 〉 | 통과 (0.01ms, 10.2MB) |
테스트 18 〉 | 통과 (0.00ms, 10.1MB) |
풀이(3) 100/100
위 방식으로 아예 로직을 바꾼 것 말고 짝코딩 시간에 split() 과 split("")의 차이를 배울 수 있었다!
ChatGPT 방식 말고 기존 풀이에서 문제점 중 하나가 공백 처리를 잘못한 것인데 이는 split() 과 split("")의 차이를 구분하지 않고 사용해서 문제였다.
split() 을 쓰게되면 공백을 기준으로 문자열을 나눠 리스트에 추가한다.
반면 split("")을 쓰게 되면 공백을 통으로 나누는게 아니라 각 공백도 하나의 기준으로 잡고 개별적으로 쪼개준다.
s = 'ane adsate aete asdf'
print(s)
print(s.split())
print(s.split(" "))
위와 같이 공백도 하나의 빈 문자열로 리스트에 담기는 것을 알 수 있다.
이를 활용한 풀이는 다음과 같다.
def solution(s):
words = s.split(" ")
# print(words)
nums = ['0', '1', '2', '3', '4', '5', '6', '7','8', '9']
tmp = []
for word in words:
if word == '':
tmp.append(word)
elif word[0] in nums:
to_append = word[0] + word[1:].lower()
tmp.append(to_append)
else:
to_append = word[0].upper() + word[1:].lower()
tmp.append(to_append)
answer = ' '.join(tmp)
return answer
그리고 여기서 착각했던 부분이 있는데.
split(" ")을 이용해서 리스트로 반환하면 공백을 그대로 리스트에 넣는 것이 아니라 빈 문자열로 넣어주는 것이다.
그래서 if word == '': (빈문자열) 와 if word ==' ' (공백)을 생각없이 썼다가 런타임에러가 계속 발생하였다.
해결하고 나서 모든 테스트 케이스를 통과하였다.
테스트 1 〉 | 통과 (0.01ms, 10.2MB) |
테스트 2 〉 | 통과 (0.01ms, 10.3MB) |
테스트 3 〉 | 통과 (0.01ms, 10.1MB) |
테스트 4 〉 | 통과 (0.01ms, 10.1MB) |
테스트 5 〉 | 통과 (0.01ms, 10.1MB) |
테스트 6 〉 | 통과 (0.01ms, 10.2MB) |
테스트 7 〉 | 통과 (0.01ms, 10.2MB) |
테스트 8 〉 | 통과 (0.01ms, 10.2MB) |
테스트 9 〉 | 통과 (0.01ms, 10.2MB) |
테스트 10 〉 | 통과 (0.01ms, 10MB) |
테스트 11 〉 | 통과 (0.02ms, 10.1MB) |
테스트 12 〉 | 통과 (0.01ms, 10.2MB) |
테스트 13 〉 | 통과 (0.01ms, 10.2MB) |
테스트 14 〉 | 통과 (0.01ms, 10.1MB) |
테스트 15 〉 | 통과 (0.02ms, 10.3MB) |
테스트 16 〉 | 통과 (0.01ms, 10.1MB) |
테스트 17 〉 | 통과 (0.01ms, 10.3MB) |
테스트 18 〉 | 통과 (0.00ms, 10.1MB) |
4. 주요 코드 및 정리
4.1 주요 함수
(1) 문자열.split(): 문자열을 공백을 기준으로 나눠 리스트 형태로 만들기(공백은 리스트에 포함되지 않음)
words = s.split()
(2) 문자열.split(" "): 문자열을 공백을 기준으로 나눠 리스트 형태로 만들기(공백을 빈 문자열로 포함됨)
word = s.split(" ")
(3) 문자열.lower(), 문자열.upper(): 문자열 대문자 소문자 바꾸기
# 문자열 소문자로 변경
s.lower()
# 문자열 대문자로 변경
s.upper()
(4) 문자열.isspace()
문자열이 공백인지 아닌지 판별
s.isspace()
마지막은 string type이 아니기때문에오류가 발생한다.
4.2 정리
나름 문자열을 쉽게 풀어보려고 단어 단위로 쪼개는 발상은 나쁘지 않았다고 생각한다.
하지만 편한 방법이라고 생각이 들더라도 내가 해결하지 못하는 edge case(어쩌면 여기는 다수 case였다!)를 고려를 반드시 해야한다.
특히 숨어있는 조건이 있을 수 있으므로 '극한'의 case를 고려하는 것을 잊지 말 것!
'Career > Coding Test' 카테고리의 다른 글
99클럽 코테 스터디 5/99일차 TIL #전화번호 목록(비기너) (0) | 2024.07.26 |
---|---|
99클럽 코테 스터디 5/99일차 TIL #전화번호 목록(미들러) (0) | 2024.07.26 |
99클럽 코테 스터디 3/99일차 TIL # 숫자 문자열과 영단어(챌린저) (0) | 2024.07.24 |
99클럽 코테 스터디 3/99일차 TIL # 문자열 내 마음대로 정렬하기(미들러) (3) | 2024.07.24 |
99클럽 코테 스터디 2/99일차 TIL # 숫자 카드 나누기(챌린저) (0) | 2024.07.23 |
소중한 공감 감사합니다