자바스크립트에서 문자열을 다룰 때 정규표현식(Regular Expression)은 빠질 수 없는 강력한 도구입니다. 보통 우리는 /pattern/gi와 같은 리터럴(Literal) 방식을 사용하여 정적 패턴을 정의하곤 하죠.
하지만 실무에서는 매칭해야 할 패턴이 코드 작성 시점이 아닌 런타임(Runtime)에 결정되는 경우가 많습니다. 예를 들어 사용자가 입력한 검색어를 하이라이팅하거나, 특정 파라미터로 넘어온 금칙어를 필터링해야 하는 상황입니다. 이때 많은 주니어 개발자들이 다음과 같은 실수를 하곤 합니다.
const text = "안a녕A하a세A요"; const letter = "A"; // ❌ 의도한 대로 작동하지 않습니다. // 변수 letter가 아닌 문자열 "letter" 자체를 찾으려고 시도합니다. const result = text.replace(/letter/gi, " ");
위 코드의 결과는 원본 문자열 그대로입니다. 리터럴 방식의 슬래시(/ /) 안에는 변수를 직접 넣을 수 없기 때문입니다.
이 문제를 해결하기 위해서는 자바스크립트가 제공하는 정규표현식의 또 다른 생성 방식인 생성자 함수(new RegExp)를 사용해야 합니다.
리터럴 방식과 생성자 방식은 각각 장단점이 뚜렷합니다.
우리의 목적은 동적 패턴 생성이므로 생성자 함수를 선택하는 것이 타당합니다.
new RegExp(pattern, flags) 문법을 사용하면 첫 번째 인자로 문자열을 전달할 수 있습니다. 자바스크립트 엔진은 이 문자열을 평가하여 내부적인 정규식 객체를 생성합니다.
생성자 방식을 사용할 때 가장 중요한 포인트는 이스케이프(Escaping)입니다. 리터럴에서는 \d라고 쓰면 되지만, 문자열에서는 `` 자체가 특수문자이므로 "\\d"와 같이 두 번 써줘야 정규식 엔진에 정상적으로 전달됩니다.
이제 변수를 안전하게 전달하여 정규식을 처리하는 함수를 구현해 보겠습니다.
/** * 특정 문자를 동적으로 받아 공백으로 치환하는 함수 */ const replaceDynamicLetter = (text: string, letter: string): string => { // 변수 letter를 생성자의 첫 번째 인자로, 플래그를 두 번째 인자로 전달 const regex = new RegExp(letter, "gi"); return text.replace(regex, " "); }; const source = "안a녕A하a세A요a저a는A신a승A훈a입a니A다"; console.log(replaceDynamicLetter(source, "A")); // 결과: "안 녕 하 세 요 저 는 신 승 훈 입 니 다"
만약 변수 letter에 . 이나 * 같은 정규식 특수문자가 들어온다면 의도치 않은 매칭이 발생할 수 있습니다. 이를 방지하기 위해 Regex Escape 유틸리티를 함께 사용하는 것이 시니어 레벨의 정석입니다.
const escapeRegExp = (str: string) => { return str.replace(/[.*+?^${}()|[]]/g, '\\$&'); // 특수문자 앞에 \ 추가 }; const safeReplace = (text: string, pattern: string) => { const safePattern = escapeRegExp(pattern); const regex = new RegExp(safePattern, "gi"); return text.replace(regex, " "); };
new RegExp를 남발하면 매번 컴파일이 발생하여 성능이 저하될 수 있습니다. 가능한 경우 컴파일된 객체를 재사용(Memoization)해야 합니다.\\w, \\s), 패턴이 복잡해질수록 가독성이 리터럴에 비해 떨어집니다.변수를 활용한 정규표현식 처리는 단순해 보이지만, 생성자 함수의 동작 원리와 문자열 이스케이프의 함정을 정확히 이해해야 버그 없는 견고한 코드를 짤 수 있습니다.
단순히 기능을 구현하는 것을 넘어, 보안과 성능까지 고려하는 시니어의 관점에서 동적 패턴을 다루어 보시길 바랍니다!
참고 자료: