2024. 1. 17. 22:12ㆍPS
[ 작성 이유 ]
앞에선 Regex사용방법을 배웠으니 이제 Regex를 실제로 필요한 상황에 적용 시켜보자.
[ 카카오 2018년 다트게임 ]
카카오 2018년 다트 게임에서는 총 3번의 다트를 던질 기회가 있으며 각각의 경우 0-10점을 얻을 수 있다. 점수와 관련해서 영역이 있는데 Single(S)은 1제곱, Double(D)는 2제곱, Triple(T)는 3제곱으로 점수를 계산한다. 또한 스타상(*)과 아차상(#)이 있는데 스타상은 해당 점수와 이전 점수를 2배로, 아차상은 해당 점수만큼 마이너스 시킨다. 이들 정보로 구성된 문자열이 들어왔을 때 점수 결과를 출력해라.
입력 예시
1. 1S2D*3T 37 1^1*2 + 2^2*2 + 3^3
2. 1D2S#10S 9 1^2+2^1(-1) + 10^1
3. 1D2S0T 3 1^2 + 2^1 + 0^3
해당 문제를 잘 풀기 위해서는 어차피 기회가 3번인거 파싱만 깔끔하게 하면 문제가 굉장히 쉬워진다. 그런데 파싱을 어떻게 할 지가 곤란하다. 1번은 [1S, 2D*, 3T], 2번은 [1D,2S#,10S], 3번은 [1D,2S,0T] 이렇게 파싱되면 참 편할 것 같다.
바로 생각나는 데로 임의로 만들어봤는데 생각보다 시간이 오래 걸리고 코드도 길다.
def parse(dartResult):
token = []
ptr = 0
for i in range(3):
num = ""
cal = ""
prize = ""
while True:
if(ptr == len(dartResult)):
break
if(ord(dartResult[ptr]) >= ord('0') and ord(dartResult[ptr]) <= ord('9')):
if(len(cal) != 0):
break
num = num + dartResult[ptr]
ptr += 1
elif(dartResult[ptr] == 'S' or dartResult[ptr] == 'D' or dartResult[ptr] == 'T'):
cal = cal + dartResult[ptr]
ptr += 1
else:
prize = prize + dartResult[ptr]
ptr += 1
break
token.append(num+cal+prize)
return token
이걸 이제 Regex를 이용해서 풀어보자. 우선 숫자와 관련해서는 0부터 10까지 무조건 1개 등장할 수 있고 이후에는 S, D, T가 무조건 1개 등장한 뒤 #이나 *는 등장할 수도 있고 안할 수도 있다.
pattern = re.compile(r'([0-9]|10)([SDT])(\*\#)?')
print(pattern.findall('1S2D*3T'))
이렇게 단 두 줄이면 위에서 한 고생을 안해도 된다. 해당 부분이 3파트로 나뉘어져있으니 for문을 돌면서 내부용 변수 3개를 위에 내가 설정한 것처럼 num, cal, prize 이렇게 두고 나머지 계산 부분만 하면 동일하다.
[ 카카오 2018년 뉴스 클러스터링 ]
두 문자열 "FRANCE"와 "FRENCH"가 주어졌을 때 두 글자씩 끊어서 {FR, RA, AN, NC, CE}, {FR, RE, EN, NC, CH}로 만들어서 문제 조건에 따라서 검사를 해야한다. 그런데 들어오는 문자열은 대소문자 구분이 없고 두글자씩 끊었을 때 영어가 아닌 문자가 들어가면 집합에 포함시키지 않는다.
그렇기 때문에 저렇게 리스트 구성요소를 만들기만 한다면 매우 쉽겠지만 문제는 반복문으로 슬라이싱을 해도 저게 맞는지 아닌지 조건 검사하기가 까다롭다. 그 때 정규식을 사용하면 편하다. 정규식은 매우 간단하다 어차피 난 문자열 모두 다 LowerCase로 바꿔버릴거고 '[a-z]{2}'만 만족하면 원하는데로 끊을 수 있다. 그래서 다음과 같이 파싱을 하였다.
def solution(str1, str2):
str1 = str1.lower()
str2 = str2.lower()
str1List = []
str2List = []
pattern = re.compile(r'[a-z]{2}')
for i in range(len(str1)-1):
stream = str1[i] + str1[i+1]
if pattern.findall(stream):
str1List.append(stream)
for i in range(len(str2)-1):
stream = str2[i] + str2[i+1]
if pattern.findall(stream):
str2List.append(stream)
이렇게 하면 원하는 Regex 규칙에 따라서 해당 string이 포함되는지를 상대적으로 간단하게 확인할 수 있다. 물론 a-z까지 그냥 배열에 26짜리로 넣어서 순환하는 함수를 만들어도 되긴하지만 개인적으로 이 방법도 익혀두고 싶었다.
[ 정리 ]
앞선 글에서 Regex를 이용해서 문자열에서 원하는 패턴을 찾아 파싱하는 방법을 익혔다. 또한 이 글에서는 그걸 이용한 코테 문제 두 개로 단순히 문자열 내부에서 파싱만 해도 되는 경우, 중간에 고정된 길이의 겹쳐있는 것을 찾아야하는 경우 어떻게 처리할지를 확인했다. 이것보다 한 단계 더 진화한 경우로 글자수가 정해져있지 않고 겹치게 찾아야 하는 경우는 문제가 있다면 나중에 고민을 해보고 올리겠다.
[ 참고 자료 ]
'PS' 카테고리의 다른 글
파이썬 Regex 사용법 (0) | 2024.01.17 |
---|---|
Visual Studio 한글 에러 해결법 (0) | 2024.01.15 |