로그 파일에서 에러 줄만 뽑아내려고 정규식을 검색해 본 적이 있을 겁니다. 스택오버플로에서 그럴듯한 한 줄을 복사해 붙였는데 아무것도 안 잡히고, 기호 하나씩 고쳐 가며 삼십 분을 태우는 그 과정 말입니다. 정규식은 AI에게 맡기기 가장 좋은 작업 중 하나입니다. 문법이 까다롭고, 사람이 외우기엔 비효율적이며, 정답인지 아닌지를 기계적으로 검증할 수 있기 때문입니다.
다만 조건이 하나 붙습니다. AI가 준 정규식을 그대로 믿고 쓰면 조용히 잘못된 데이터를 뽑아냅니다. 이 글에서는 쓸 만한 정규식이 나오는 프롬프트 작성법, 받은 결과를 30초 만에 검증하는 테스트 틀, 그리고 AI가 반복적으로 틀리는 지점 다섯 가지를 정리합니다.
AI가 정규식에 강한 이유, 그리고 믿으면 안 되는 이유
정규식은 학습 데이터가 압도적으로 많은 영역입니다. 이메일, URL, 날짜, 전화번호처럼 흔한 패턴이라면 AI가 거의 정확한 답을 냅니다. 사람이 손으로 쓰는 것보다 빠르고, 자주 빼먹는 이스케이프도 잘 챙깁니다.
문제는 정규식의 실패 방식이 유난히 조용하다는 데 있습니다.
- 문법 오류가 아니라 의미 오류로 실패합니다. 코드는 정상 실행되고, 결과만 틀립니다.
- 매칭돼야 할 것이 안 잡히면 금방 알아채지만, 매칭되면 안 되는 것이 잡히는 경우는 며칠 뒤 데이터가 이상해지고 나서야 발견됩니다.
- AI는 자기 정규식을 실제로 실행해 보지 않습니다. 설명은 그럴듯한데 패턴은 설명과 다른 경우가 드물지 않습니다.
실패하는 프롬프트와 되는 프롬프트
대부분의 실패는 AI 성능이 아니라 입력 정보 부족에서 옵니다. 아래처럼 물으면 AI는 로그 형식을 마음대로 가정하고 답을 만듭니다.
[ 잘 안 되는 프롬프트 ]
로그에서 날짜랑 에러 메시지 뽑는 정규식 좀 만들어줘
같은 질문을 이렇게 바꾸면 결과가 달라집니다. 핵심은 실제 데이터와 매칭되면 안 되는 예시를 같이 주는 것입니다.
[ 잘 되는 프롬프트 ]
파이썬 re 모듈용 정규식을 만들어 주세요.
입력은 아래 형식의 로그 한 줄입니다.
2026-09-11 INFO 서버 시작
2026-09-11 ERROR DB 연결 실패
요구사항
- 날짜는 YYYY-MM-DD 형식만 허용 (26-09-11 같은 두 자리 연도는 거부)
- 레벨은 INFO, WARN, ERROR 세 가지만 허용 (DEBUG는 거부)
- 메시지는 한글/공백 포함, 줄 끝까지
- 각 부분을 date, level, msg 라는 이름 있는 그룹으로 뽑을 것
- 줄 전체가 정확히 일치할 때만 매칭 (fullmatch 기준)
정규식과 함께, 매칭돼야 하는 예시 3개와
매칭되면 안 되는 예시 3개도 같이 알려 주세요.
특히 “매칭되면 안 되는 예시”가 중요합니다. 정규식은 너무 넓게 잡는 쪽으로 틀리는 경우가 훨씬 많은데, 경계 사례를 미리 알려 주면 AI가 앵커와 문자 클래스를 좁혀서 만들어 줍니다. 두 자리 연도, 존재하지 않는 로그 레벨처럼 아슬아슬하게 비슷한 것을 고르는 게 요령입니다.
그대로 복사해 쓰는 프롬프트 템플릿
매번 처음부터 쓰기 번거로우니, 아래 틀을 스니펫으로 저장해 두고 빈칸만 채워 쓰면 됩니다.
아래 조건에 맞는 정규식을 만들어 주세요.
1. 사용 환경: (파이썬 re / 자바스크립트 / grep -E / VS Code 찾기 중 하나)
2. 매칭 대상 예시 (실제 데이터 3줄 이상 그대로 붙여넣기):
...
3. 매칭되면 안 되는 예시 (경계에 있는 것으로 3줄):
...
4. 뽑아내야 할 값과 그룹 이름:
...
5. 제약: 줄 전체 일치 여부, 대소문자 구분 여부, 여러 줄 처리 여부
답변에는 정규식 한 줄과, 각 부분이 무엇을 하는지 한 줄 설명,
그리고 바로 돌려볼 수 있는 테스트 코드를 포함해 주세요.
1번 항목을 빼먹지 마세요. 정규식은 언어마다 방언이 다른데, 사용 환경을 안 적으면 AI는 보통 가장 기능이 풍부한 문법으로 답합니다. 그게 파이썬에서 안 돌아가는 이유가 됩니다.
받은 정규식은 반드시 테스트로 확인합니다
AI가 정규식을 주면 눈으로 읽어서 검증하려 들지 마세요. 정규식을 사람이 읽어서 검증하기 어렵다는 게 애초에 AI에게 맡긴 이유입니다. 대신 기대하는 입력과 기대하지 않는 입력을 나열해서 돌려 보는 편이 빠르고 확실합니다.
# regex_test.py -- AI가 준 정규식을 붙여넣고 바로 돌려보는 틀
import re
# 여기에 AI가 준 정규식을 그대로 붙여넣습니다.
PATTERN = r'(?P<date>\d{4}-\d{2}-\d{2})\s+(?P<level>INFO|WARN|ERROR)\s+(?P<msg>.+)'
# 매칭돼야 하는 입력과, 그룹에서 기대하는 값
SHOULD_MATCH = [
('2026-09-11 INFO 서버 시작', {'level': 'INFO', 'date': '2026-09-11'}),
('2026-09-11 ERROR DB 연결 실패', {'level': 'ERROR'}),
]
# 매칭되면 안 되는 입력 (경계 사례를 일부러 넣습니다)
SHOULD_NOT_MATCH = [
'2026-09-11 DEBUG 상세 로그',
'26-09-11 INFO 두 자리 연도',
'아무 형식도 아닌 줄',
]
rx = re.compile(PATTERN)
fail = 0
for text, expect in SHOULD_MATCH:
m = rx.fullmatch(text)
if not m:
print('매칭 실패:', text)
fail += 1
continue
for key, want in expect.items():
got = m.group(key)
if got != want:
print('그룹 불일치:', text, '|', key, '->', got, '(기대:', want, ')')
fail += 1
for text in SHOULD_NOT_MATCH:
if rx.fullmatch(text):
print('매칭되면 안 되는데 매칭됨:', text)
fail += 1
print('통과' if fail == 0 else '실패 ' + str(fail) + '건')
이 파일 하나를 만들어 두고 PATTERN과 두 목록만 바꿔 가며 재사용하면 됩니다. 여기서 match가 아니라 fullmatch를 쓴 점이 중요합니다. re.match는 문자열 앞부분만 맞아도 통과시키기 때문에, 뒤에 쓰레기 값이 붙은 줄을 잡아내지 못합니다.
브라우저에서 바로 확인하고 싶다면 regex101.com이 편합니다. 왼쪽에서 파이썬·자바스크립트·PCRE 등 문법(flavor)을 골라야 실제 환경과 같은 결과가 나옵니다.
AI가 자주 틀리는 다섯 가지 지점
아래는 실제로 반복해서 나오는 오류 유형입니다. 검증할 때 이 다섯 가지부터 확인하면 대부분 걸러집니다.
| 틀리는 지점 | 어떻게 나타나는가 | 확인 방법 |
|---|---|---|
| 앵커 누락 | \d{4}가 “20261”에도, “abc2026″에도 매칭됨 | fullmatch로 테스트하거나 ^...$가 있는지 확인 |
| 그룹 번호와 설명 불일치 | 설명은 “두 번째 그룹이 도메인”인데 실제로는 세 번째 | 번호 대신 이름 있는 그룹((?P<name>...))을 요구 |
점(.)이 줄바꿈을 안 먹음 | 여러 줄 로그에서 .+가 첫 줄 끝에서 멈춤 | 여러 줄이 대상이면 re.DOTALL 필요 여부를 명시 |
| 이스케이프 빠짐 | .이 리터럴 점이 아니라 “아무 문자”로 동작 | 문자 클래스 밖의 ., +, ?를 눈으로 훑기 |
\d의 범위 | 파이썬3에서 \d는 아랍·데바나가리 숫자까지 매칭 | 숫자만 원하면 [0-9]를 쓰거나 re.ASCII 지정 |
언어마다 문법이 다릅니다
가장 자주 겪는 함정입니다. AI에게 환경을 말하지 않으면 자바스크립트나 PCRE 기준으로 답하는 경우가 많은데, 파이썬 re 모듈은 지원 범위가 더 좁습니다.
import re
# 파이썬 re 모듈은 길이가 고정된 lookbehind만 지원합니다.
re.compile(r'(?<=USER-)\d+') # OK, 'USER-' 는 길이 5로 고정
re.compile(r'(?<=USER-\d*)abc') # 에러가 납니다
# re.error: look-behind requires fixed-width pattern
# 자바스크립트는 같은 패턴이 그냥 동작합니다. 그래서
# "ChatGPT에서 받아서 잘 되던 정규식"을 파이썬에 옮기면 여기서 터집니다.
파이썬에서 가변 길이 lookbehind가 꼭 필요하다면 표준 re 대신 서드파티 regex 패키지를 쓰는 방법이 있습니다. 다만 의존성이 하나 늘어나므로, 대부분은 정규식을 두 단계로 나누거나 문자열 처리로 푸는 편이 낫습니다.
성능 함정: 정규식 한 줄이 서버를 멈출 수 있습니다
중첩된 수량자((a+)+처럼 반복 안에 반복이 들어간 형태)는 입력이 조금만 길어져도 실행 시간이 폭발합니다. 백트래킹이 기하급수적으로 늘어나기 때문인데, 이걸 ReDoS(정규식 서비스 거부)라고 부릅니다.
import re, time
rx = re.compile(r'^(a+)+$')
for n in (20, 22, 24):
text = 'a' * n + 'b' # 마지막 b 때문에 절대 매칭되지 않습니다
start = time.time()
rx.match(text)
print(n, '->', round(time.time() - start, 3), '초')
# a를 하나 늘릴 때마다 소요 시간이 대략 두 배로 늘어납니다.
# 이 입력이 사용자 입력이라면, 짧은 문자열 하나로 서버 스레드가 묶입니다.
AI가 만든 정규식에서도 이런 형태가 종종 나옵니다. 특히 “이메일 주소를 완벽하게 검증하는 정규식”을 요청했을 때 길고 복잡한 패턴이 돌아오는데, 그중 일부가 이 구조를 갖고 있습니다. 사용자 입력을 받는 자리라면 반드시 최대 길이를 먼저 제한하세요.
이메일은 정규식으로 완벽하게 검증할 수 없습니다. 실무에서는
@가 하나 있는지 정도만 보고, 실제 유효성은 인증 메일을 보내서 확인하는 쪽이 정석입니다.
참고로 Go의 regexp 패키지나 Rust의 regex 크레이트는 백트래킹을 쓰지 않는 엔진이라 이 문제가 구조적으로 없습니다. 대신 lookahead·lookbehind 같은 기능을 지원하지 않습니다. 트레이드오프가 있다는 점만 알아 두면 됩니다.
마무리
오늘 당장 할 수 있는 건 하나입니다. 위 regex_test.py를 스니펫으로 저장해 두세요. 다음에 AI에게 정규식을 받으면 붙여넣고 한 번 돌리는 데 30초면 충분하고, 그 30초가 잘못된 데이터를 며칠 뒤에 발견하는 상황을 막아 줍니다.
정리하면 순서는 이렇습니다. 실제 데이터와 반례를 함께 주고, 사용 환경을 명시하고, 받은 결과는 눈이 아니라 테스트로 확인한다. 이 세 가지만 지켜도 정규식에 쓰는 시간이 크게 줄어듭니다.
다음 글에서는 파이썬으로 API 응답을 다룰 때 자주 만나는 JSONDecodeError가 실제로는 어떤 상황에서 나는지, 그리고 원인별 해결법을 정리해 보겠습니다.
“AI로 정규식(Regex) 만드는 법 — 그대로 믿으면 안 되는 이유와 검증 절차”에 대한 1개의 생각