Python/Python Challenge

[Python Challenge 2] 책책책 책을 읽읍시다.

Python Challenge 2의 url은 다음과 같다.

Python challenge 2 : http://www.pythonchallenge.com/pc/def/ocr.html

 

ocr

 

www.pythonchallenge.com


구성

페이지 번역은 다음과 같다. 힌트는 쓰지 않겠다.

 

"문자를 인식하시오. 책 안에 있을 수도 있으나, 혹시 Page Source에 있을 수도 있습니다."

 

말장난이다. Page가 장임을 이용해서 BOOK과 소속 관계를 2ke2ke하는거 같은데, Page Source안에는 다음과 같은 주석을 찾을 수 있다.

엄청많은 특수문자들이 있고, 위에 한 줄 주석으로 다음의 값 중 희귀한 값을 뽑아 보라고 한다. 코딩 타임이다.


해결 아이디어

문자열이 너무 길어 2.dat에 저장하였고, 개행 문자는 다 ""로 치환했다. 문자열이 약 10만 개 정도 되는데, 이는 순차 탐색이나, 간단한 명령어로도 반복 효율이 1초 이하로 나오기 때문에, set으로 변환을 해서 distinct 한 값으로 변환하고 이를 count 해서 가장 적게 나온 값을 출력했다.

if __name__=="__main__" :

    with open("2.dat","r") as f:
        raw_string = f.read().replace("\n","")

    raw_set = set(list(raw_string))
    raw_dict = {x:raw_string.count(x) for x in raw_set}

    new_dict = sorted(raw_dict.items(),key=(lambda x:x[1]))
    
    for i in new_dict :
        print(i[0],end="")

출력은 아래와 같았다.

>>> 
eutqilya^*&{$+!%}[_#](@)

응? 이게 무슨 글자지? 문제는 여기서 발생한다. set은 순서 없는 자료구조이다 보니, 아마 글자에서 나온 순서대로 보여준 게 아닐 거다. 코드를 조금 추가해서 eutqilya가 코드에 나온 순서로 정렬되게 바꾸자

if __name__=="__main__" :

    with open("2.dat","r") as f:
        raw_string = f.read().replace("\n","")

    raw_set = set(list(raw_string))
    raw_dict = {x:raw_string.count(x) for x in raw_set}

    new_dict = sorted(raw_dict.items(),key=(lambda x:x[1]))
    
    for i in new_dict :
        print(i[0],end="")

    target_string = "eutqilya"
    answer_list = list()
    for i in range(len(target_string)) :
        answer_list.append([target_string[i],raw_string.find(target_string[i])])

    answer_list = sorted(answer_list,key=(lambda x:x[1]))
    
    print("")
    
    for item in answer_list :
        print(item[0],end="")
    

출력은 다음과 같다.

>>> 
utylaqie^*&${+!%}[_#](@)
equality

찾았다 요놈

 

Answer Url : http://www.pythonchallenge.com/pc/def/equality.html


여담으로 이문제를 쉽게 해결하는 방법은 모듈인 collections을 활용하는 방법이다. 필자가 위에서 뻘짓을 한걸 미리 구현해 둔 모듈이다. collections을 활용한 풀이는 다음과 같다.

import collections


if __name__ == "__main__" :
    with open("2.dat","r") as f:
        res = f.read().replace("\n","")
        
    ans = collections.Counter(res)
    print(ans.most_common())

출력은 아래와 같다.

>>> 
[(')', 6186), ('@', 6157), ('(', 6154), (']', 6152), ('#', 6115), ('_', 6112), 
('[', 6108), ('}', 6105), ('%', 6104), ('!', 6079), ('+', 6066), ('$', 6046), 
('{', 6046), ('&', 6043), ('*', 6034), ('^', 6030), 
('e', 1), ('q', 1), ('u', 1), ('a', 1), ('l', 1), ('i', 1), ('t', 1), ('y', 1)]