CASE-009
그렙 앤 코 데이터 탐정 사무소
의뢰서
의뢰인
한별 소장
증거물
사무소의 낡은 금고, 새 비밀번호 후보 여섯 개, 금고 안 장부.
해결 조건
새 비밀번호 규칙(8자 이상, 숫자·소문자·특수문자 하나씩)을 패턴 하나로 검사하고, 장부 금액에 천 단위 쉼표를 넣는다.
소장이 구석의 낡은 금고 앞에 쪼그려 앉습니다. "백트래커가 금고 얘기를 한 건 그냥 겁주려는 거야. 그래도 비밀번호는 오늘 바꾼다. 이번에는 규칙을 제대로 지켜서."
새 비밀번호 규칙은 세 가지입니다. 순서는 상관없습니다.
규칙 1. 8자 이상
규칙 2. 숫자, 소문자, 특수문자가 각각 하나 이상
규칙 3. 이 모든 걸 정규식 하나로 검사한다
후보:
vault2026!
vault2026
VAULT2026!
v!2
longpassword!
safe#2026box카드에 적혀 있던 말이 떠오릅니다. "모두 같은 자리에서 확인할 수 있다면." 오늘 배울 문법이 바로 그것입니다.
4교시의 ^ $ \b를 다시 떠올려 봅시다. 이들은 글자를 하나도 먹지 않고 "여기가 시작인가", "여기가 단어 경계인가"라는 위치만 확인했습니다. 이런 매치를 폭 0(zero-width) 매치라고 합니다.
re.findall(r"\b", "hi yo") # ['', '', '', '']
re.sub(r"\b", "|", "hi yo") # '|hi| |yo|'\b가 찾은 것은 빈 문자열 네 개, 즉 위치 네 개입니다. 오늘 배울 전후방 탐색은 이 "위치 확인"을 내가 원하는 조건으로 만드는 문법입니다.
X(?=Y)는 "뒤에 Y가 오는 X"를 찾습니다. Y는 확인만 하고 매치에 포함하지 않습니다. 이것을 전방 탐색(lookahead)이라고 합니다.
re.findall(r"\d+(?=원)", "3000원짜리 5개, 합계 15000원") # ['3000', '15000']5개의 5는 뒤에 원이 없어서 빠졌고, 찾은 숫자에 원은 들어 있지 않습니다. "원으로 끝나는 숫자"를 찾되 숫자만 꺼내고 싶을 때 딱 맞습니다.
증거 분석실
re.search(r"", text)
돌려준 값
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가 아닌지 확인합니다.비밀번호 규칙처럼 "이것도, 저것도, 그것도 있어야 한다"는 조건은 전방 탐색을 나란히 붙여서 씁니다.
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)
돌려준 값
도트의 한마디
전방 탐색은 앞을 슬쩍 보기만 하고 발은 움직이지 않아요. 저도 창틀에 앉아 밖을 내다보기만 하지, 넘어가지는 않거든요. 그래서 몇 번을 내다봐도 제자리예요.
방향을 뒤집으면 후방 탐색(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)
돌려준 값
금고 안의 장부 숫자가 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)
돌려준 값
검사기를 완성하고 후보를 걸러 냅니다.
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 통과소장은 통과한 두 개 중 어느 것도 고르지 않습니다. "후보 목록에 적힌 순간 비밀번호가 아니야." 그러고는 규칙을 통과하는 새 비밀번호를 아무도 보지 않게 직접 정하고, 검사기만 사무소 공용 도구 상자에 넣어 둡니다.
사건 종결 보고서 — 금고 비밀번호 규칙을 전방 탐색 세 개로 검사하는 도구를 만듦. 후보 여섯 개 중 두 개만 규칙을 통과함. 비밀번호는 소장이 따로 교체함. 장부 금액에 천 단위 쉼표를 넣어 정리함.
"price: 1200won, tax: 120won"에서 won 앞의 숫자만 전방 탐색으로 꺼내 보세요.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)) 처럼 전방 탐색 안의 그룹으로 겹치는 매치를 꺼낼 수 있다.
새 교시·새 강의 소식 받기
이 강의에 새 교시가 더해지거나 이어지는 강의가 열리면 이메일로 알려 드려요.
R
ReflexKR
눌러 보며 배우는 파이썬과 Reflex. 모든 예제는 Reflex 0.10.0에서 직접 실행해 확인했습니다.
ReflexKR은 배너 광고 없이 무료로 운영돼요. 도움이 되셨다면 커피 한 잔으로 응원해 주세요.
© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
질문과 답변
이 교시에서 궁금한 점을 남겨 주세요. 모든 언어 페이지의 질문이 함께 모입니다.