from collections import defaultdict
import re
from decimal import Decimal
def solution(word, pages) :
word = word.lower()
web = defaultdict(defaultdict)
link_score = defaultdict(int)
url_pattern = re.compile('<meta property=\"og:url\" content=\"(.+?)"')
body_pattern = re.compile(r'\<body>\n(.+?)\n\</body>', re.S)
ext_url_pattern = re.compile('<a href="(.+?)"')
for index, page in enumerate(pages) :
page = page.lower()
url = url_pattern.findall(page).pop()
web[url]['index'] = index
body = ' '.join(body_pattern.findall(page))
web[url]['ext_url'] = ext_url_pattern.findall(body)
web[url]['basic_score'] = Decimal(str(re.sub('[^a-z]', '.', body).split('.').count(word)))
for ext_url in web[url]['ext_url'] :
link_score[ext_url] += web[url]['basic_score'] / len(web[url]['ext_url'])
return sorted([[val['basic_score'] + link_score[url], val['index']] for url, val in web.items()], key = lambda x : (-x[0], x[1]))[0][1]
정규식 활용의 필수성
이거 정규식 아예 모르면 절대로 풀 수 없는 문제다. 정규식때문에 대가리 깨질뻔했지만, 검색해가며 어찌어찌 해결했다. 일단 웹페이지 구성을 알아야한다.
web page
<html lang="ko" xml:lang="ko" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<meta property="og:url" content="https://b.com"/>
</head>
<body>
Suspendisse potenti. Vivamus venenatis tellus non turpis bibendum,
<a href="https://a.com"> Link to a </a>
blind sed congue urna varius. Suspendisse feugiat nisl ligula, quis malesuada felis hendrerit ut.
<a href="https://c.com"> Link to c </a>
</body>
</html>
page url
이 나오는 위치 =<meta property="og:url" content="이곳"
words
&외부링크
가 나오는 위치 =<body> 이곳 </body>
body
태그 안에외부링크
가 나오는 위치 =<a href="이곳"
pages
에서 우리에게 필요한 정보를 뽑기위해 정규식 패턴을 만들어야한다.
url_pattern = re.compile('<meta property=\"og:url\" content=\"(.+?)"') body_pattern = re.compile(r'\<body>\n(.+?)\n\</body>', re.S) ext_url_pattern = re.compile('<a href="(.+?)"')
이 패턴이 이해되지 않으면 정규식 공부를 먼저 해야한다. 알아둬서 좋은수준이아니고 꼭 알아야 다음 코딩테스트 때 쉽게 문제를 풀 수 있을 것이다. 정규식을 이용한 문제는 자주 나온다.
이 패턴들을 이용해 re.findall
로 필요한 문자열을 뽑아내야한다.
web dictionary
각 웹페이지의 정보들을 저장할 자료구조가 필요하다.
web = {'url1' : {'index' : 웹페이지 번호, 'ext_url' : 외부 링크, 'basic_score' : 기본점수}, 'url2' : {'index' : 웹페이지 번호, 'ext_url' : 외부 링크, 'basic_score' : 기본점수}} link_score = {'url1' : link_score, 'url2' : link_score}
web
,ext_score
의 자료구조 내부는 이 자료들을 저장한다.
score
구해야하는 매칭점수는 basic score
, link score
다. basic score
는 각 웹페이지의 body
문에서 구하면 되지만, link score
는 다른 웹페이지로부터 받아야한다. 그렇게되면 반복문 2번을 돌려야하는데 차라리
각 웹페이지의 외부 링크의
link score
를 구해서 외부 웹페이지의link score
에 더해준다.
이렇게하면 pages
의 각 웹페이지를 한바퀴만 돌면 web
, link_score
가 구해진다.
from collections import defaultdict
import re
from decimal import Decimal
def solution(word, pages) :
word = word.lower()
web = defaultdict(defaultdict)
link_score = defaultdict(int)
url_pattern = re.compile('<meta property=\"og:url\" content=\"(.+?)"')
body_pattern = re.compile(r'\<body>\n(.+?)\n\</body>', re.S)
ext_url_pattern = re.compile('<a href="(.+?)"')
for index, page in enumerate(pages) :
page = page.lower()
url = url_pattern.findall(page).pop() # url을 뽑아낸다.
web[url]['index'] = index # url's index
body = ' '.join(body_pattern.findall(page)) # body문 뽑아낸다.
web[url]['ext_url'] = ext_url_pattern.findall(body) # #body 문안의 모든 외부링크 뽑아낸다.
web[url]['basic_score'] = Decimal(str(re.sub('[^a-z]', '.', body).split('.').count(word))) # basic score
for ext_url in web[url]['ext_url'] : #모든 외부 링크에대해 Link score를 구한 후 해당 웹페이지의 link score 갱신
link_score[ext_url] += web[url]['basic_score'] / len(web[url]['ext_url'])
'''
복잡해 보이는 코드지만, 각 웹페이지의 [기본점수 + 링크점수] 리스트를 만들어 정렬한 후 가장큰 매칭점수를 뽑는 코드다.
'''
return sorted([[val['basic_score'] + link_score[url], val['index']] for url, val in web.items()], key = lambda x : (-x[0], x[1]))[0][1]