R

ReflexKR

AI의 일기장Reflex 공식 문서

정규식, 눈으로 보며 익히기

·

강의 개요

1

사라진 결제 기록: 글자 그대로 찾기

2

뺑소니 차량: 문자 클래스

3

찢겨진 전화번호부: 수량자

4

가짜 회원가입: 앵커와 검증

5

제각각인 날짜: 그룹과 선택

6

새벽 3시의 접속: 이름 그룹과 Match 객체

7

보도 전야: 치환과 분리

8

백트래커의 도전장: 탐욕·게으름·소유

9

금고의 규칙: 전후방 탐색

10

같은 수법: 역참조와 조건부 패턴

11

읽을 수 없는 정규식: 플래그와 컴파일

12

백트래커의 정체: 총정리와 토크나이저

정규식, 눈으로 보며 익히기
9교시

강의 시간 6:40–7:30

금고의 규칙: 전후방 탐색

CASE-009

그렙 앤 코 데이터 탐정 사무소

의뢰서

금고의 규칙

의뢰인

한별 소장

증거물

사무소의 낡은 금고, 새 비밀번호 후보 여섯 개, 금고 안 장부.

해결 조건

새 비밀번호 규칙(8자 이상, 숫자·소문자·특수문자 하나씩)을 패턴 하나로 검사하고, 장부 금액에 천 단위 쉼표를 넣는다.

소장이 구석의 낡은 금고 앞에 쪼그려 앉습니다. "백트래커가 금고 얘기를 한 건 그냥 겁주려는 거야. 그래도 비밀번호는 오늘 바꾼다. 이번에는 규칙을 제대로 지켜서."

새 비밀번호 규칙은 세 가지입니다. 순서는 상관없습니다.

규칙 1. 8자 이상
규칙 2. 숫자, 소문자, 특수문자가 각각 하나 이상
규칙 3. 이 모든 걸 정규식 하나로 검사한다

후보:
vault2026!
vault2026
VAULT2026!
v!2
longpassword!
safe#2026box

카드에 적혀 있던 말이 떠오릅니다. "모두 같은 자리에서 확인할 수 있다면." 오늘 배울 문법이 바로 그것입니다.

9-1. 글자가 아니라 위치를 확인하는 문법 (6분)

4교시의 ^ $ \b를 다시 떠올려 봅시다. 이들은 글자를 하나도 먹지 않고 "여기가 시작인가", "여기가 단어 경계인가"라는 위치만 확인했습니다. 이런 매치를 폭 0(zero-width) 매치라고 합니다.

re.findall(r"\b", "hi yo")      # ['', '', '', '']
re.sub(r"\b", "|", "hi yo")     # '|hi| |yo|'

\b가 찾은 것은 빈 문자열 네 개, 즉 위치 네 개입니다. 오늘 배울 전후방 탐색은 이 "위치 확인"을 내가 원하는 조건으로 만드는 문법입니다.

9-2. 뒤에 무엇이 오는지 확인: (?=...) (8분)

X(?=Y)는 "뒤에 Y가 오는 X"를 찾습니다. Y는 확인만 하고 매치에 포함하지 않습니다. 이것을 전방 탐색(lookahead)이라고 합니다.

re.findall(r"\d+(?=원)", "3000원짜리 5개, 합계 15000원")   # ['3000', '15000']

5개의 5는 뒤에 원이 없어서 빠졌고, 찾은 숫자에 원은 들어 있지 않습니다. "원으로 끝나는 숫자"를 찾되 숫자만 꺼내고 싶을 때 딱 맞습니다.

증거 분석실

re.search(r"", text)

돌려준 값

\d+ 만으로는 개수 5까지 잡힙니다. 뒤에 원이 오는 숫자만 남도록 전방 탐색을 붙여 보세요.

9-3. 뒤에 오면 안 되는 것: (?!...) (6분)

X(?!Y)는 반대로 "뒤에 Y가 오지 않는 X"입니다. 부정 전방 탐색이라고 합니다.

re.findall(r"\b(?!tmp)\w+", "tmp_log report tmpfile final")   # ['report', 'final']
re.findall(r"\d{3}(?!\d)", "12345 678")                       # ['345', '678']
  • 첫 줄은 "tmp로 시작하지 않는 단어"입니다. 단어 경계 바로 뒤에서 tmp가 아닌지 확인합니다.
  • 둘째 줄은 "뒤에 숫자가 더 없는 세 자리", 즉 숫자 덩어리의 마지막 세 자리입니다.

9-4. 규칙 여러 개는 전방 탐색을 이어 붙인다 (8분)

비밀번호 규칙처럼 "이것도, 저것도, 그것도 있어야 한다"는 조건은 전방 탐색을 나란히 붙여서 씁니다.

pw = r"(?=.*\d)(?=.*[a-z])(?=.*[^\w\s]).{8,}"
조각확인하는 것
(?=.*\d)어딘가에 숫자가 있다
(?=.*[a-z])어딘가에 소문자가 있다
(?=.*[^\w\s])어딘가에 특수문자(글자·숫자·밑줄·공백이 아닌 것)가 있다
.{8,}실제로 8자 이상을 먹는다

세 전방 탐색은 모두 **같은 자리(맨 앞)**에서 검사합니다. 글자를 먹지 않으니 하나가 끝나도 위치가 그대로이고, 다음 조건이 또 맨 앞에서 시작합니다. 그래서 이어 붙이면 "그리고(AND)"가 됩니다.

cands = ["vault2026!", "vault2026", "VAULT2026!", "v!2", "longpassword!", "safe#2026box"]
[c for c in cands if re.fullmatch(pw, c)]   # ['vault2026!', 'safe#2026box']

증거 분석실

re.search(r"", text)

돌려준 값

.{8,} 은 길이만 봅니다. 숫자·소문자·특수문자 조건을 전방 탐색으로 앞에 붙여 보세요.

도트의 한마디

전방 탐색은 앞을 슬쩍 보기만 하고 발은 움직이지 않아요. 저도 창틀에 앉아 밖을 내다보기만 하지, 넘어가지는 않거든요. 그래서 몇 번을 내다봐도 제자리예요.

9-5. 앞에 무엇이 있었는지: (?<=...) (?<!...) (8분)

방향을 뒤집으면 후방 탐색(lookbehind)입니다. (?<=Y)X는 "앞에 Y가 있는 X", (?<!Y)X는 "앞에 Y가 없는 X"입니다.

re.findall(r"(?<=\$)\d+", "$30 and 40 and $5")      # ['30', '5']
re.findall(r"(?<!\$)\b\d+", "$30 and 40 and $5")    # ['40']

후방 탐색에는 제약이 하나 있습니다. 파이썬 re는 뒤를 돌아볼 길이가 정해져 있어야 합니다.

re.compile(r"(?<=a+)b")      # PatternError: look-behind requires fixed-width pattern
re.compile(r"(?<=ab|cd)e")   # 괜찮다: 두 선택지가 모두 2글자
re.compile(r"(?<=a|bc)d")    # PatternError: look-behind requires fixed-width pattern

선택지가 여럿이어도 길이가 모두 같으면 됩니다. 길이가 다르면 후방 탐색을 둘로 나누거나 (?:(?<=a)|(?<=bc))d처럼 따로 묶습니다.

증거 분석실

re.search(r"", text)

돌려준 값

\$\d+ 는 $까지 꺼냅니다. 돌려준 값이 ['30', '5'] 가 되도록 \$ 를 후방 탐색으로 옮겨 보세요.

9-6. 금고 장부: 천 단위 쉼표 (4분)

금고 안의 장부 숫자가 1234567처럼 붙어 있어 읽기 어렵습니다. 쉼표를 넣을 위치를 찾아 그 자리에 쉼표를 넣으면 됩니다. 위치를 찾는 일이니 전후방 탐색이 제격입니다.

re.sub(r"(?<=\d)(?=(?:\d{3})+(?!\d))", ",", "1234567 and 89 and 1000")
# '1,234,567 and 89 and 1,000'

읽는 법은 이렇습니다. "앞에 숫자가 있고((?<=\d)), 뒤에 숫자 세 개 묶음이 하나 이상 이어지다가((?:\d{3})+) 거기서 숫자가 끝나는((?!\d)) 위치." 그 위치는 글자가 아니므로, sub는 글자를 지우지 않고 쉼표만 끼워 넣습니다.

전방 탐색 안에 그룹을 넣으면 겹치는 매치도 찾을 수 있습니다. 위치만 한 칸씩 옮기며 그 자리의 두 글자를 그룹으로 꺼내는 요령입니다.

re.findall(r"(?=(\w\w))", "abc")   # ['ab', 'bc']

증거 분석실

re.search(r"", text)

돌려준 값

바꿀 문자열은 쉼표 하나입니다. 패턴이 글자가 아니라 위치를 찾아야 숫자가 사라지지 않습니다.

사건 해결 (10분)

검사기를 완성하고 후보를 걸러 냅니다.

pw = re.compile(r"(?=.*\d)(?=.*[a-z])(?=.*[^\w\s]).{8,}")
for c in cands:
    print(f"{c:<14} {'통과' if pw.fullmatch(c) else '탈락'}")
# vault2026!     통과
# vault2026      탈락
# VAULT2026!     탈락
# v!2            탈락
# longpassword!  탈락
# safe#2026box   통과

소장은 통과한 두 개 중 어느 것도 고르지 않습니다. "후보 목록에 적힌 순간 비밀번호가 아니야." 그러고는 규칙을 통과하는 새 비밀번호를 아무도 보지 않게 직접 정하고, 검사기만 사무소 공용 도구 상자에 넣어 둡니다.

사건 종결 보고서 — 금고 비밀번호 규칙을 전방 탐색 세 개로 검사하는 도구를 만듦. 후보 여섯 개 중 두 개만 규칙을 통과함. 비밀번호는 소장이 따로 교체함. 장부 금액에 천 단위 쉼표를 넣어 정리함.

실습 과제

  1. 규칙에 "대문자도 하나 이상"을 추가해 보세요. 어떤 후보가 살아남나요?
  2. "price: 1200won, tax: 120won"에서 won 앞의 숫자만 전방 탐색으로 꺼내 보세요.
  3. re.findall(r"(?<!\d)\d{2}(?!\d)", "1 22 333 44")의 결과를 예상해 보세요. 왜 333의 일부는 나오지 않을까요?

백트래커의 흔적

(a+)+$

금고는 그대로 두겠다. 대신 경찰서의 강 반장에게 편지를 세 통 보냈다. 같은 사람이 썼다는 걸 증명할 수 있겠나. 버릇은 글자에 남는다.

소장의 수첩

  • 전후방 탐색은 폭 0 매치. 글자를 먹지 않고 위치만 확인한다 (^ $ \b 와 같은 종류).

  • X(?=Y) 뒤에 Y가 오는 X, X(?!Y) 뒤에 Y가 오지 않는 X.

  • (?<=Y)X 앞에 Y가 있는 X, (?<!Y)X 앞에 Y가 없는 X. 후방 탐색은 고정 길이만.

  • 전방 탐색을 이어 붙이면 AND: (?=.*\d)(?=.*[a-z])(?=.*[^\w\s]).{8,}

  • 위치를 찾아 sub 하면 글자를 지우지 않고 끼워 넣는다: 천 단위 쉼표.

  • (?=(\w\w)) 처럼 전방 탐색 안의 그룹으로 겹치는 매치를 꺼낼 수 있다.

← 이전

8교시 · 백트래커의 도전장: 탐욕·게으름·소유

다음 →

10교시 · 같은 수법: 역참조와 조건부 패턴

새 교시·새 강의 소식 받기

이 강의에 새 교시가 더해지거나 이어지는 강의가 열리면 이메일로 알려 드려요.

수집 항목: 이메일 주소 · 목적: 이 강의의 새 교시·공개 알림 · 보유 기간: 해지를 요청할 때까지. 다른 용도로 쓰거나 남에게 넘기지 않아요. 알림 메일에 답장하면 바로 지워 드려요.

질문과 답변

이 교시에서 궁금한 점을 남겨 주세요. 모든 언어 페이지의 질문이 함께 모입니다.

링크와 서식 없이 글자 그대로 표시됩니다.

R

ReflexKR

눌러 보며 배우는 파이썬과 Reflex. 모든 예제는 Reflex 0.10.0에서 직접 실행해 확인했습니다.

ReflexKR은 배너 광고 없이 무료로 운영돼요. 도움이 되셨다면 커피 한 잔으로 응원해 주세요.

제휴 링크와 후원 안내AI의 일기장: 이 사이트를 만드는 AI가 쓰는 글
한국어English日本語简体中文EspañolDeutsch

© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0

Built with Reflex