Emacs Lisp에서 정규표현식 매치 문자열을 안전하게 넘기는 방법

Emacs, Emacs Lisp // 2025년 10월 11일 작성

어느 날 Emacs를 편하게 쓸 목적의 Lisp 코드를 작성하다 (늘 그랬다 시피) 또 정규표현식에서 가로막혔다. 어떤 변수를 정규표현식에서 매치시켜야 되는데 확신이 안 들었기 때문이다. 왜냐하면 '정규표현식에 특정 문자열이 일치하는지를 확인하고 싶은데 해당 문자열에 정규표현식용 특수 문자가 포함되어 있다면 어떻게 해야 할까?'라는 걱정 때문이었다.

정확한 질문

정확한 요구사항은 Emacs Lisp으로 Org 문서에 항목 추가하기 (삽질기)와 연결되는 내용으로, 할 일(TODO)이 잔뜩 기록된 Org Mode 파일에서 원하는 파일 경로가 포함된 TODO 항목을 검색하는 것이 목표였다.

그래서 아래와 같은 코드를 작성했다.

(goto-char (point-min))
(re-search-forward (concat "^\\*\\* TODO \\[\\[file:" 
                           current-file 
                           "\\]\\]$"))

그런데 위 코드에서 다뤄지는 current-file이라는 변수는 파일의 경로를 담고 있다. 그리고 하필이면 파일 경로에는 정규표현식에서 특수하게 사용하는 문자들이 포함될 수 있다. 예를 들어 /. 같은 문자들 말이다. 따라서 그냥 매개변수 문자열로 일치 여부를 파악하면 오동작할 가능성이 높아 보였다.

이 문제를 원하는 대로 동작하게 하는 방법이 있을까?

정규표현식용 문자열 이스케이프

위 질문의 답은 단 하나의 함수로 해결되었다.

해답: regexp-quote

시작부터 해답을 내놔버렸는데 굳이 이상한 내용만 길게 언급하다가 마지막에 해답을 내놓을 필요는 없을 것 같다. 어쨌든 이 regexp-quote 함수는 이름 처럼 특정 문자열에서 정규표현식용 특수 문자들을 이스케이프(escape)해서 돌려주는 함수이기 때문에 딱 적당한 용도의 함수다.

결과적으로 위 질문의 코드는 아래와 같이 고칠 수 있었다.

(goto-char (point-min))
(re-search-forward (concat "^\\*\\* TODO \\[\\[file:" 
                           (regexp-quote current-file) 
                           "\\]\\]$"))

이렇게 고치니 예상대로 그리고 기대대로 동작하였다.

결론 및 여담

regexp-quote 함수를 사용하면 정규표현식 매치 문자열을 안전하게 넘겨줄 수 있다.

regexp-quote 함수를 알게 된 이후로 개인적으로 사용하던 온갖 야매(?) 코드들을 수정해야 되었다. 불의의 사고(?) 같은 느낌이었지만 그래도 '이런게 있었다는 것을 진작 알았다면 안 했을 그런 온갖 하드코딩의 잔해들'을 안심할 수 있는 코드들로 바꿀 수 있었기에 기꺼이 즐길 수 있었던 노동 같았다.

역시 새로 알아간다는 것은 즐거운 일이다. 그리고 몰라서 더 힘들었다는 것도 알아가는 것이 참... 아아...

Seorenn (Konrad Seo)
개발자 주제에 경제나 먹거리 관련 글을 주로 쓰는 사람