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

목표
- 다중 단어 쿼리 지원
- 전체 구문 일치 우선
- 개별 토큰 일치로 폴백
- DOM에서 결과 하이라이트
와블록 건너뛰기
머릿속에선: “쉽다. 그냥 정규식을 만들면 돼.”
1단계: 정규식 만들기
사용자가 다음을 검색한다면:
power shell
다음과 같은 패턴을 생성한다:
power[\s\u00A0]+shell|power|shell
논리
- 먼저 전체 구문을 매치한다.
- 실패하면 개별 토큰을 매치한다.
종이 위에서는 깔끔해 보이고, 독립적으로는 동작한다.
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단계: 두 번의 패스?
과정을 나눠볼 생각을 했다:
- 구문 매치를 시도한다.
- 찾지 못하면 토큰 매치를 시도한다.
간단해 보이지만, 첫 번째 패스 후에 DOM이 이미 변형될 수 있어 패스 간 상태 관리가 필요하다.
깨달음
- 정규식 문제는 독립적으로는 쉽다.
- DOM 변형 문제도 독립적으로는 쉽다.
- 두 가지를 결합하면 복잡도가 곱해진다.
“간단한 기능”과 “미니 검색 엔진” 사이의 경계는 매우 얇다.
현재 상황
- 검색이 대부분 동작한다.
- 하이라이트가 적용된다.
- 보호된 블록은 건너뛴다.
- 구조가 유지된다.
아직 완전한 브라우저 수준의 Ctrl + F는 아니지만 핵심 기능은 구현됐다.
이제 DOM을 이전보다 훨씬 더 존중하게 되었고, 살아있는 DOM 트리 안에서 JavaScript 로직을 예측 가능하게 만드는 것이 진짜 도전임을 깨달았다.
배운 점
- 정규식은 결정적이지만, DOM은 구조적이고 상태를 가진다.
- 텍스트 노드를 교체하기 시작하면 모든 것이 섬세해진다.
- 엣지 케이스, 상태 관리, 견고한 변형 처리 등이 진정으로 신뢰할 수 있는 기능을 만들기 위해 필수적이다.