2021년 08월 25일 TIL
https://programmers.co.kr/learn/courses/30/lessons/42893
오늘은 19년도 카카오 블라인드 문제 매칭 점수 문제를 풀었다.
문자열 문제였는데, 정규 표현식을 사용하면 굉장히 깔끔하게 풀리는 문제였지만, 그렇게 풀지 않아서 굉장히 지저분하게 풀었다.
이후 정규표현식을 좀 더 공부할 필요를 느껴서, 조금 더 공부하고 코드를 깔끔하게 수정해보았다.
정규표현식
Pattern 클래스 주요 메서드
1. Compile(String regix)
주어진 정규표현식으로 패턴을 만듭니다.
2. matcher(CharSequence input)
대상 문자열이 패턴과 일치할 경우 true를 반환합니다.
3. asPredicate()
문자열을 일치시키는데 사용할 수 있는 술어를 작성합니다.
4. pattern()
컴파일된 정규표현식을 String 형태로 반환합니다.
5. split(CharSequence input)
문자열을 주어진 인자값에 따라 분리합니다.
Parttern 플래그 값 사용(상수)
- Pattern.CANON_EQ : None표준화된 매칭 모드를 활성화합니다.
- Pattern.CASE_INSENSITIVE : 대소문자를 구분하지 않습니다.
- Pattern.COMMENTS : 공백과 #으로 시작하는 주석이 무시됩니다. (라인의 끝까지).
- Pattern.MULTILINE : 수식 ‘^’ 는 라인의 시작과, ‘$’ 는 라인의 끝과 match 됩니다
- Pattern.DOTALL : 수식 ‘.’과 모든 문자와 match 되고 ‘\n’ 도 match 에 포함됩니다.
- Pattern.UNICODE_CASE : 유니코드를 기준으로 대소문자 구분 없이 match 시킵니다.
- Pattert.UNIX_LINES : 수식 ‘.’ 과 ‘^’ 및 ‘$’의 match시에 한 라인의 끝을 의미하는 ‘\n’만 인식됩니다.
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Solution {
static Map<String, Page> map = new HashMap<>();
public static int solution(String word, String[] pages) {
int idx = 0;
for (String html : pages) {
Page page = new Page(idx++, html.toLowerCase());
page.setBaseScore(word.toLowerCase());
page.setLinkCount();
map.put(page.url, page);
}
for (Page page : map.values()) {
page.setLinkScore();
}
List<Page> list = new ArrayList<>(map.values());
Collections.sort(list);
return list.get(0).idx;
}
static class Page implements Comparable<Page> {
int idx;
int baseScore = 0;
int linkCnt = 0;
double linkScore = 0;
String html;
String url;
Page(int idx, String html) {
this.idx = idx;
this.html = html;
findURL();
}
private void findURL() {
Pattern pattern = Pattern
.compile("<meta property=\"og:url\" content=\"https://(.+?)\"/>");
Matcher matcher = pattern.matcher(html);
while (matcher.find()) {
this.url = matcher
.group(1); // () 로 그룹 지정, 이 경우에는 https://과 " 사이에 있는 임의의 문자열을 (.+?) 뽑음.
}
}
public void setBaseScore(String word) {
int idx = html.indexOf(word); // 존재하지 않으면 -1 반환
while (idx != -1) {
char pre = html.charAt(idx - 1); // 단어 앞뒤로 Character인지 체크
char post = html.charAt(idx + word.length());
if (!Character.isLowerCase(pre) && !Character
.isLowerCase(post)) {// 앞뒤로 알파벳 소문자인지 확인, page 객체 생성시에 lowercase로 넣어서 대문자는 없음
baseScore++;
}
idx = html.indexOf(word, idx + 1); // 그 다음 인덱스부터 찾기
}
}
public void setLinkCount() {
int idx = html.indexOf("<a href="); // 존재하지 않으면 -1 반환
while (idx != -1) {
linkCnt++;
idx = html.indexOf("<a href=", idx + 1);
}
}
public void setLinkScore() {
Pattern pattern = Pattern.compile("<a href=\"https://(.+?)\">");
Matcher matcher = pattern.matcher(html);
while (matcher.find()) {
String hyperLink = matcher.group(1);
if (map.containsKey(hyperLink)) {
map.get(hyperLink).linkScore += (double) baseScore / linkCnt;
}
}
}
@Override
public int compareTo(Page o) {
return Double.compare(o.baseScore + o.linkScore, this.baseScore + this.linkScore);
}
}
}