코딩연습

(javascript) 매칭 점수

Realuda72 2025. 9. 15. 23:05

https://school.programmers.co.kr/learn/courses/30/lessons/42893

 

프로그래머스

SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

 정규식을 적극적으로 활용해서 문제를 풀었다.

 평소에 문자열 다루는걸 싫어해서 피해왔는데, 이정도로 문자열을 다루기는 처음인 것 같다.

 javascript의 정규식을 이용해서 비교적 간단하게 풀었지만, 만약 c나 c++이나 c#으로 풀었다면 어떻게 했을지 상상만 해도 끔찍하다.

 

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp

 

RegExp - JavaScript | MDN

There are two ways to create a RegExp object: a literal notation and a constructor. The literal notation takes a pattern between two slashes, followed by optional flags, after the second slash. The constructor function takes either a string or a RegExp obj

developer.mozilla.org

 정규식과 관련해서는 공식 문서와 GEMINI를 통해서 공부했다.

 

 Regex의 match 메서드와 matchAll 메서드 사용법을 배웠다.

 match 메서드는 정규식에 g 플래그가 쓰였는지에 따라 반환값이 달라진다. 만약 정규식에 g 플래그를 사용했다면 정규식에 해당하는 전체 표현이 반환되고, 캡쳐링 그룹은 포함되지 않는다. 만약 정규식에 g 플래그를 사용하지 않았다면 정규식에 해당하는 전체 표현과 캡쳐링 그룹이 반환된다. 이 경우 exec와 같은 반환값을 가진다.

 match 메서드만을 가지고는 모든 캡쳐링 그룹을 찾을 수 없으므로 matchAll 메서드를 사용해야한다.

 

 matchAll 메서드는 마치 exec가 null을 반환할때까지 반복 수행하는것과 같은 반환값을 가진다. matchAll의 반환값은 iterable iterator object형태를 가진다. 이 값은 그대로 쓸 수는 없지만 이 값을 순회하면 마치 exec를 수행한 것과 같은 값을 가질 수 있다.

// 두가지 방식으로 호출할 수 있다.
let matchs = "abcabcdabcde".matchAll(/a/g);
let matchs2 = /a/g[Symbol.matchAll]("abc");

// matchAll의 결과인 matchs를 순회하여 사용할 수 있다.
for(var match of matchs){
    // match는 Symbol.exec(/a/g)의 결과와 같다.
    console.log(match[0]); // "a"
    console.log(match[1]); // 만약 캡쳐링 그룹이 있다면 첫번째 캡쳐링 그룹을 출력한다.
    console.log(match[2]); // 만약 캡쳐링 그룹이 있다면 두번째 캡쳐링 그룹을 출력한다.
    console.log(match[index]); // 0
    console.log(match[input]); // "abcabcdabcde"
}

 

 아직 exec를 제대로 써보지 못해서 어색하지만, 여러번 쓰다보면 익숙해질 것이다.

 

코드

function solution(word, pages) {
    var answer = 0;

    // pages에서 객체 구성
    // 각 요소는 page_idx : [page_url, base_score, #link, link_score]
    var page_info = {};

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

        // 페이지에서 기본 데이터 추출 (page_idx : [page_url, base_score, #link, link_score])
        var page_url = "";
        var base_score = 0;

        // url 추출
        let regex = /<meta property="og:url" content="([^"]*)"/;
        let match = page.match(regex);
        if (match && match[1]) {
            page_url = match[1];
        }

        // 기본 점수 추출
        regex = new RegExp(`(?<![a-z])${word}(?![a-z])`, 'gi');
        match = page.match(regex);
        base_score = match ? match.length : 0;

        page_info[i] = [page_url, base_score, 0, 0]
    }

    for (var i = 0; i < pages.length; i++) {
        var page = pages[i];
        var page_url = page_info[i][0];
        var base_score = page_info[i][1];

        // 링크 갯수 추출
        var link_count = 0;
        var regex = /<a href="([^"]*)"/g;
        var match = Array.from(page.matchAll(regex), (x) => x[1]);
        link_count = match ? match.length : 0;
        page_info[i][2] = link_count;

        // 링크 점수계산
        for (var link of match) {
            for (var j = 0; j < Object.keys(page_info).length; j++) {
                if (page_info[j][0] === link) {
                    page_info[j][3] += base_score / link_count;
                    break;
                }
            }
        }
    }

    // 결과 반환
    for (var i = 0; i < Object.keys(page_info).length; i++) {
        if (page_info[i][1] + page_info[i][3] > page_info[answer][1] + page_info[answer][3]) answer = i;
    }

    return answer;
}

'코딩연습' 카테고리의 다른 글

(C#) 지형 편집  (0) 2025.09.17
(C#) 등산코스 정하기  (0) 2025.09.17
(javascript) 경주로 건설  (0) 2025.09.12
(javascript) 외벽 점검  (0) 2025.09.11
(javascript) 행렬과 연산  (6) 2025.08.07