[프로그래머스] 42893. 매칭 점수

4 분 소요

문제 링크

[프로그래머스] 42893. 매칭 점수


풀이 과정

문자열을 파싱해 원하는 부분만을 뽑아낼 수 있는 지를 확인하는 문제입니다.

<meta>, <a>, <body> 태그 내부에서의 문자열 검색은 모두 indexOf 메소드를 사용했습니다.


static void setUrl(Info[] infos, int index, String page) {
    String search = "<meta property=\"og:url\" content=\"";
    int url_start_idx = page.indexOf(search) + search.length();
    int url_end_idx = url_start_idx + page.substring(url_start_idx).indexOf("\"/>");

    String url = page.substring(url_start_idx, url_end_idx);

    infos[index].url = url;
}

위의 setUrl 메소드는 태그 내의 content 속성 값을 뽑아내어 배열 요소에 저장하는 과정을 거칩니다. 태그의 포맷으로 search 라는 이름의 변수를 하나 지정한 뒤, 이 문자열이 끝나는 지점의 인덱스를 구합니다. 해당 인덱스가 url의 시작 인덱스가 되며, substring 과 indexOf 메소드를 통해 끝나는 지점의 인덱스도 구할 수 있습니다.


static void setExternalLinks(Info[] infos, int index, String page) {
    ArrayList<String> externalLinks = new ArrayList<>();
    String search = "<a href=\"";
    String tmp = page;

    while (tmp.indexOf(search) != -1) {
        int a_start_idx = tmp.indexOf(search) + search.length();
        int a_end_idx = a_start_idx + tmp.substring(a_start_idx).indexOf("\">");

        String externalLink = tmp.substring(a_start_idx, a_end_idx);
        externalLinks.add(externalLink);

        tmp = tmp.substring(a_end_idx);
    }
    infos[index].externalLinks = externalLinks;
    infos[index].externalLinkCnt = externalLinks.size();
}

외부 링크는 <a> 태그로 이루어져 있습니다. setExternalLinks 메소드는 <body> 태그 내에 존재하는 <a> 태그들을 검색합니다. 하나 이상의 여러 <a> 태그가 존재할 수 있으므로, while 문을 통해 모두 검색하도록 합니다. 외부 링크 주소를 잘라내어 배열 요소 객체 내의 ArrayList에 추가하고, 그 개수도 저장합니다.


static void setBasicScore(Info[] infos, int index, String page, String word) {
    String search = "<body>";
    int body_start_idx = page.indexOf(search) + search.length();
    int body_end_idx = body_start_idx + page.substring(body_start_idx).indexOf("</body>");

    String body = page.substring(body_start_idx, body_end_idx).toUpperCase();
    body = body.toUpperCase();
    word = word.toUpperCase();

    int cnt = 0;
    int find = body.indexOf(word);

    while (find != -1) {
        char prev = body.charAt(find - 1);
        char next = body.charAt(find + word.length());

        if (!Character.isLetter(prev) && !Character.isLetter(next)) {
            cnt++;
        }

        find = body.indexOf(word, find + 1);
    }

    infos[index].basicScore = cnt;
}

setBasicScore 메소드는, <body> 태그 내부에 word 문자열과 매칭되는 단어들의 개수를 세어 저장하는 메소드입니다. 예를 들어, 검색어가 “aba” 인 경우, “abab abababa”는 단어 단위로 매칭되지 않으므로, 그 개수는 0이 됩니다. 이런 과정은 단어의 바로 전과 후가 알파벳인지를 확인하는 isLetter 메소드로 확인할 수 있습니다.


코드

import java.util.ArrayList;
import java.util.Arrays;

public class Main {
    public static int solution(String word, String[] pages) {
        int answer = 0;

        Info[] infos = new Info[pages.length];
        for (int i = 0; i < infos.length; i++) {
            infos[i] = new Info(i);
        }

        for (int i = 0; i < pages.length; i++) {
            String page = pages[i];

            setUrl(infos, i, page);
            setExternalLinks(infos, i, page);
            setBasicScore(infos, i, page, word);
        }

        for (int i = 0; i < infos.length; i++) {
            double total = 0;
            for (int j = 0; j < infos.length; j++) {
                if (i == j) continue;

                if (infos[j].externalLinks.contains(infos[i].url)) {
                    total += (double) infos[j].basicScore / infos[j].externalLinkCnt;
                }
            }

            infos[i].linkScore = total;
            infos[i].matchingScore = infos[i].basicScore + infos[i].linkScore;
        }

        Arrays.sort(infos);

        answer = infos[0].index;

        return answer;
    }

    static void setUrl(Info[] infos, int index, String page) {
        String search = "<meta property=\"og:url\" content=\"";
        int url_start_idx = page.indexOf(search) + search.length();
        int url_end_idx = url_start_idx + page.substring(url_start_idx).indexOf("\"/>");

        String url = page.substring(url_start_idx, url_end_idx);

        infos[index].url = url;
    }

    static void setExternalLinks(Info[] infos, int index, String page) {
        ArrayList<String> externalLinks = new ArrayList<>();
        String search = "<a href=\"";
        String tmp = page;

        while (tmp.indexOf(search) != -1) {
            int a_start_idx = tmp.indexOf(search) + search.length();
            int a_end_idx = a_start_idx + tmp.substring(a_start_idx).indexOf("\">");

            String externalLink = tmp.substring(a_start_idx, a_end_idx);
            externalLinks.add(externalLink);

            tmp = tmp.substring(a_end_idx);
        }
        infos[index].externalLinks = externalLinks;
        infos[index].externalLinkCnt = externalLinks.size();
    }

    static void setBasicScore(Info[] infos, int index, String page, String word) {
        String search = "<body>";
        int body_start_idx = page.indexOf(search) + search.length();
        int body_end_idx = body_start_idx + page.substring(body_start_idx).indexOf("</body>");

        String body = page.substring(body_start_idx, body_end_idx).toUpperCase();
        body = body.toUpperCase();
        word = word.toUpperCase();

        int cnt = 0;
        int find = body.indexOf(word);

        while (find != -1) {
            char prev = body.charAt(find - 1);
            char next = body.charAt(find + word.length());

            if (!Character.isLetter(prev) && !Character.isLetter(next)) {
                cnt++;
            }

            find = body.indexOf(word, find + 1);
        }

        infos[index].basicScore = cnt;
    }

    static class Info implements Comparable<Info> {
        String url;
        ArrayList<String> externalLinks;
        int index, basicScore, externalLinkCnt;
        double linkScore, matchingScore;

        public Info(int index) {
            this.index = index;
        }

        @Override
        public int compareTo(Info o) {
            return this.matchingScore == o.matchingScore ? this.index - o.index : Double.compare(o.matchingScore, this.matchingScore);
        }
    }

    public static void main(String[] args) {
//        solution("blind", new String[]{"<html lang=\"ko\" xml:lang=\"ko\" xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n  <meta charset=\"utf-8\">\n  <meta property=\"og:url\" content=\"https://a.com\"/>\n</head>  \n<body>\nBlind Lorem Blind ipsum dolor Blind test sit amet, consectetur adipiscing elit. \n<a href=\"https://b.com\"> Link to b </a>\n</body>\n</html>", "<html lang=\"ko\" xml:lang=\"ko\" xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n  <meta charset=\"utf-8\">\n  <meta property=\"og:url\" content=\"https://b.com\"/>\n</head>  \n<body>\nSuspendisse potenti. Vivamus venenatis tellus non turpis bibendum, \n<a href=\"https://a.com\"> Link to a </a>\nblind sed congue urna varius. Suspendisse feugiat nisl ligula, quis malesuada felis hendrerit ut.\n<a href=\"https://c.com\"> Link to c </a>\n</body>\n</html>", "<html lang=\"ko\" xml:lang=\"ko\" xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n  <meta charset=\"utf-8\">\n  <meta property=\"og:url\" content=\"https://c.com\"/>\n</head>  \n<body>\nUt condimentum urna at felis sodales rutrum. Sed dapibus cursus diam, non interdum nulla tempor nec. Phasellus rutrum enim at orci consectetu blind\n<a href=\"https://a.com\"> Link to a </a>\n</body>\n</html>"});
        solution("Muzi", new String[]{"<html lang=\"ko\" xml:lang=\"ko\" xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n  <meta charset=\"utf-8\">\n  <meta property=\"og:url\" content=\"https://careers.kakao.com/interview/list\"/>\n</head>  \n<body>\n<a href=\"https://programmers.co.kr/learn/courses/4673\"></a>#!MuziMuzi!)jayg07con&&\n\n</body>\n</html>", "<html lang=\"ko\" xml:lang=\"ko\" xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n  <meta charset=\"utf-8\">\n  <meta property=\"og:url\" content=\"https://www.kakaocorp.com\"/>\n</head>  \n<body>\ncon%\tmuzI92apeach&2<a href=\"https://hashcode.co.kr/tos\"></a>\n\n\t^\n</body>\n</html>"});
    }
}

카테고리:

업데이트:

댓글남기기