본문 바로가기
C.W.K.
Stream
Lesson 05 of 12 · published

Branch Reset 그룹 — (?|...)

~6 min · branch-reset, pcre, advanced

Level 0패턴 호기심
0 XP0/90 lessons0/15 achievements
0/100 XP to next level100 XP to go0% complete

선택한 분기가 달라도 같은 그룹 번호를 쓰게 할 수 있어

평범한 (a(b)c|d(e)f)에서는 바깥 전체가 그룹 1, b가 그룹 2, e가 그룹 3이야. 두 안쪽 값이 같은 역할을 해도 대안마다 괄호 위치가 달라서 번호도 달라지지.

분기 번호 초기화 그룹 (?|...)은 각 대안이 시작될 때 캡처 번호를 같은 지점으로 되돌려. (?|a(b)c|d(e)f)에서는 어느 대안이 성공하든 안쪽의 be가 그룹 1에 들어가.

여러 형식에서 같은 의미의 값을 꺼낼 때 유용해

대안이 많고 각 대안에 날짜나 식별자처럼 같은 역할의 조각이 하나씩 있다면 호출 코드는 그룹 하나만 읽으면 돼. 이 기능이 없으면 대안마다 다른 그룹을 만든 뒤 비어 있지 않은 값을 찾아야 해.

지원되는 엔진이 제한적이야

PCRE, Perl, Python의 별도 regex 모듈은 분기 번호 초기화를 지원해. Python 내장 re, JavaScript, .NET, Go에서는 이 문법을 사용할 수 없어.

중복 이름이나 후처리로 대신할 수 있어

Python regex는 대안마다 같은 이름의 캡처를 둘 수 있고, PCRE/PCRE2는 (?J)PCRE2_DUPNAMES 옵션으로 이를 허용할 수 있어. Python 내장 re는 중복 이름을 거부하므로, 각 대안을 별도 그룹으로 캡처한 뒤 코드에서 처음으로 값이 있는 그룹을 고르는 편이 이식성이 높아.

Code

분기 번호 초기화 그룹·text
# PCRE / PHP 에서
// preg_match('/(?|a(b)c|d(e)f)/', 'def', $m)
// $m[1] = 'e'  — 평탄 캡처, 어느 대안 매칭이든

# Python third-party 'regex' 모듈
import regex
m = regex.match(r'(?|a(b)c|d(e)f)', 'def')
m.group(1)  # 'e'

# 내장 Python 're' workaround — 별개 그룹 alternation
import re
m = re.match(r'(?:a(b)c|d(e)f)', 'def')
# m.group(1) 은 None (b 분기는 매칭되지 않음)
# m.group(2) 가 'e'
# 첫 non-None 선택
result = next(g for g in m.groups() if g is not None)
print(result)  # 'e'

External links

Exercise

각 대안에 내부 캡처가 하나씩 있는 패턴을 골라 분기 번호 초기화 없이 값을 꺼내는 코드와 (?|...)을 사용한 코드를 비교해. 사용 엔진의 지원 여부와 코드 스타일을 바탕으로 어느 접근을 택할지 결정해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.