<Gaj’s Latin alphabet>
사진출처: 영문 위키피디아 <Gaj’s Latin alphabet> 문서
사실 엄밀히 말하자면 위에 사진을 보듯이 크로아티아 알파벳에는 Q,W,X,Y가 없기 때문에 이 문제는 다시 정의되어야 한다.
하지만 우리는 크로아티아어를 공부하는 목적이 아니므로 그냥 문제에 집중하면
대충 내가 생각한 문제 풀기 시나리오는…
이 시나리오대로 코드를 짜면 이렇게 짤 수 있다.
cr_alphabets = ['c=','c-','dz=','d-','lj','nj','s=','z=']
inputstr = input()
for i in cr_alphabets:
if i in inputstr:
inputstr = inputstr.replace(i," ")
print(len(inputstr))
코드는 잘 짜였는지 모르겠지만 잘 돌아간다. BOJ에 제출을 하니
역시 맞았습니다! 가 날 반겨 주었다.
추가적으로 설명을 하자면 내가 모르고 있었던 replace() 문자열 메소드인데 공식문서를 살펴보면
str.replace(old, new[, count])
Return a copy of the string with all occurrences of substring old replaced by new. If the optional argument count is given, only the first count occurrences are replaced.
나의 짧고 어색한 영어로 설명해보자면 이 replace 메소드는
“원래 문자열 안에 있는 new (old를 바꿀 문자열)로 바뀐 old 라는 문자열(바뀔 문자열)의 모든 실재?들로 문자열의 복사본을 반환한다. 만약 선택적인 인수 count 가 주어진다면 첫 번째? count 실재?들만 바뀌게 된다.”
역시 영어는 어렵다. 무슨 말인지 이해가 안 된다. 코드로 돌려보자!
먼저 문자열
"돼지홍 돼지홍 돼지홍"
이 주어진다고 하자, 나는 돼지?홍이 아니기 때문에 저기 있는 “돼”를 “김”으로 바꾸고 싶다. 그러기 위해서
"돼지홍 돼지홍 돼지홍".replace("돼","김")
로 하면 되는데 위에 코드에서 old 인수 자리에는 원래 문자열 안에 있는 바꿀 문자열인 “돼” 가 오고 new 인수 자리에는 바뀔 문자열인 “김”이 된다. 이렇게 되면
"김지홍 김지홍 김지홍"
을 반환 하게 된다. 그런데 count 인수가 지금까지는 주어지지 않았다. 주어지게 되면 어떻게 될까?
"돼지홍 돼지홍 돼지홍".replace("돼","김",1)
"김지홍 돼지홍 돼지홍"
"돼지홍 돼지홍 돼지홍".replace("돼","김",2)
"김지홍 김지홍 돼지홍"
"돼지홍 돼지홍 돼지홍".replace("돼","김",3)
"김지홍 김지홍 김지홍"
그렇다. 정수인 count 인수가 주어지게 되면 문자열의 처음부터 count 인수로 들어온 값만큼의 old 인수의 문자열을 new 인수의 문자열로 바꾸는 것이다!
즉 count 인수는 문자열의 처음부터 바뀔 문자열의 개수를 의미한다. (주어지지 않았을 때는 모든 문자열을 바꾼다)
그래서 내가 구현하지 못했었던 replace() 메소드 대신 함수를 만들어 보자!
대충 내가 생각한 아이디어는
replace(string,old,new[,count]) 이고
count 인수를 받을 때는 기본값을 줘서 인수를 주지 않으면 모든 문자열을 바꾸게 할 생각이다.
내가 생각한 알고리즘은
사실 위에 알고리즘은 코드를 짜면서 생각 한 것이기 때문에 이 글을 읽는 사람에게는 이상하게 느껴질 수 있다.
답은 간단하다. 내가 만든 것 보다 더 나은 자신만의 개성 있는 코드와 알고리즘을 만들면 된다!
아무튼 코드를 대충 이런 식으로 짤 수가 있겠다.
def replace(string,old,new,count="default"):
copiedstr = string
replacedlist = [string]
while(True):
if old in copiedstr:
i_oldStart = copiedstr.index(old)
i_oldEnd= i_oldStart + len(old)
copiedstr = copiedstr[:i_oldStart] + new + copiedstr[i_oldEnd:]
replacedlist.append(copiedstr)
else:
break
if count == "default":
return replacedlist[-1]
else:
return replacedlist[count]
역시 코드가 잘 짜여진것은 모르겠지만 역시 작동은 한다.
돼지홍을 김지홍으로 바꾸기도 성공했고, Boj 문제도 성공했다.
하지만 생각보다 쉽지는 않았다. 웬만해서는 있는 replace() 문자열 메소드를 쓰는 것이 정신건강에 좋을 것 같다.
사실 이 위에 있는 두 경우는 내가 처음으로 풀기 성공한 방법이 아니다.
예전에 수능특강 pdf 파일을 단어에 네이버 사전 링크를 건 html 문서로 만들때 “크롤링”을 사용한 적이 있었다.
그 과정에서 크롤링을 할 때 정규표현식을 사용하면 더 효율적으로 크롤링을 할 수 있다는 글을 어디서 보고 시도했다가 내용의 난이도가 조금 높아서 배우는 것을 잠시 뒤로 했었다.
하지만 문자열을 처리하는데 정규표현식을 사용하면 아주 효율적이기 때문에 이번 기회에 사용하게 되었다.
정규표현식에 자세한 대한 설명은 점프투파이썬: 정규표현식 에서 보는 것이 좋을 것 같다.
정규표현식은 “특수문자를 이용해서 패턴을 만들고 이 패턴을 이용해서 문자열이 이 패턴에 맞는지 확인할 수 있게 해준다”라고 나는 이해했다.
그래서 코드를 짜보았고 이상하게? 마법처럼 작동되었다.
import re
p = re.compile("c=|c-|dz=|d-|lj|nj|s=|z=")
result = p.sub(" ",input())
print(len(result))
코드는 정말 간단하다. 일단 파이썬 정규표현식 라이브러리인 re를 가져오고 re.complie()의 인스턴스인 p를 만든다.
그러고 나서 보면 re.compile()안에 이상한 문자열이 들어 있는 게 보일 것 이다. 이 문자열이 정규표현식이다.
이 정규표현식의 뜻은 c=,c-,dz=,d-,lj,nj,s=,z=중에 하나라도 문자열 안에 있으면 match(일치?)가 된다는 소리다.
그 다음 줄의 p.sub(“ “, input()) 부분은 우리가 사용했던 replace() 메소드와 비슷한데, sub() 메소드는 input()을 이용해 문자열을 입력받고 위의 정규표현식과 match가 되면 match 된 부분을 바뀌게 될 새로운 문자열인 “ “로 바뀐 값을 반환한다. 그리고 그 다음부터는 처음의 예시와 같다.
정규표현식은 처음에 배우기에는 확실히 어렵다.
하지만 한번 봐두면 (특정한 규칙이 있는)문자열 처리가 매우 쉬워진다.
지루한? 파이썬과 약간의 알고리즘?에 대한 글이 드디어 끝이 났다. 여기까지 읽은 당신에게 박수를 보낸다.👏
이 글을 쓰면서 아직 나의 프로그래밍 수준이 많이 낮다는 것을 깨닫고 많은 문제를 해결하면서 기본기를 더 잘 갖춰야 겠다는 생각을 하게 되었다.
아무튼 저번글에서 최대 일주일에 2개의 글이 올라간다고 했었는데, 생각보다 잘 되어지지 않았고 오히려 무조건 글을 써 올려야 한다는 생각때문에 글이 잘 써지지 않았기 때문에 그냥 앞으로 글을 조금 더 자주 쓰도록 하겠다.
지난 약 2개월의 시간 동안 작은 프로젝트를 하나 진행했고 지금은 리액트로 프로젝트를 진행하던 중 나의 자바스크립트에 대한 이해가 부족하다는 것을 깨닫고 새로운 프로젝트를 진행 중이다.
그래서 현재 진행하고 있는 프로젝트가 끝나면 짤막하게 개발 후기?와 사람들의 반응을 글로 써보도록 하겠다.
그때까지 기다려 주면 좋겠다. 그럼 안녕🙋♂️
참고 자료📄
https://en.wikipedia.org/wiki/Gaj%27s_Latin_alphabet
https://www.acmicpc.net/problem/2941