Regex가 DOM을 만날 때 (그리고 갑자기 복잡해진다)

발행: (2026년 2월 26일 오후 07:03 GMT+9)
4 분 소요
원문: Dev.to

Source: Dev.to

When Regex Meets the DOM (And Suddenly It’s Not Simple Anymore) 표지 이미지

목표

  • 다중 단어 쿼리 지원
  • 전체 구문 일치 우선
  • 개별 토큰 일치로 폴백
  • DOM에서 결과 하이라이트
  • 블록 건너뛰기

머릿속에선: “쉽다. 그냥 정규식을 만들면 돼.”

1단계: 정규식 만들기

사용자가 다음을 검색한다면:

power shell

다음과 같은 패턴을 생성한다:

power[\s\u00A0]+shell|power|shell

논리

  1. 먼저 전체 구문을 매치한다.
  2. 실패하면 개별 토큰을 매치한다.

종이 위에서는 깔끔해 보이고, 독립적으로는 동작한다.

2단계: DOM에 진입

이제 문제는 단순 문자열 매치에서 DOM 순회로 옮겨간다.

작업

  • UI 요소를 피하면서 DOM을 순회한다.
  • , , , 블록을 건너뛴다.
  • 구문 강조를 유지한다.
  • 텍스트 노드만 교체하고 DOM 구조는 그대로 유지한다.

TreeWalker가 이 일을 한다:

const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
  acceptNode(node) {
    const p = node.parentElement;
    if (!p) return NodeFilter.FILTER_REJECT;

    if (p.closest("code, pre, script, style")) {
      return NodeFilter.FILTER_REJECT;
    }

    return NodeFilter.FILTER_ACCEPT;
  },
});

이제 우리는 단순히 정규식을 적용하는 것이 아니라, 제어된 DOM 변형을 수행하고 있다.

3단계: 대체 문제

구문이 대체식의 앞에 있더라도:

phrase|token1|token2

엔진은 상황에 따라 개별 토큰(power, shell, PowerShell)을 기쁘게 매치한다.

도전 과제는

  • 겹치는 매치
  • 실행 순서
  • lastIndex 재설정
  • 이중 변형 방지
  • 중첩된 “ 요소 방지

4단계: 두 번의 패스?

과정을 나눠볼 생각을 했다:

  1. 구문 매치를 시도한다.
  2. 찾지 못하면 토큰 매치를 시도한다.

간단해 보이지만, 첫 번째 패스 후에 DOM이 이미 변형될 수 있어 패스 간 상태 관리가 필요하다.

깨달음

  • 정규식 문제는 독립적으로는 쉽다.
  • DOM 변형 문제도 독립적으로는 쉽다.
  • 두 가지를 결합하면 복잡도가 곱해진다.

“간단한 기능”과 “미니 검색 엔진” 사이의 경계는 매우 얇다.

현재 상황

  • 검색이 대부분 동작한다.
  • 하이라이트가 적용된다.
  • 보호된 블록은 건너뛴다.
  • 구조가 유지된다.

아직 완전한 브라우저 수준의 Ctrl + F는 아니지만 핵심 기능은 구현됐다.

이제 DOM을 이전보다 훨씬 더 존중하게 되었고, 살아있는 DOM 트리 안에서 JavaScript 로직을 예측 가능하게 만드는 것이 진짜 도전임을 깨달았다.

배운 점

  • 정규식은 결정적이지만, DOM은 구조적이고 상태를 가진다.
  • 텍스트 노드를 교체하기 시작하면 모든 것이 섬세해진다.
  • 엣지 케이스, 상태 관리, 견고한 변형 처리 등이 진정으로 신뢰할 수 있는 기능을 만들기 위해 필수적이다.
0 조회
Back to Blog

관련 글

더 보기 »