C.W.K.
Stream
Lesson 03 of 12 · published

재귀 패턴 — (?R)

~10 min · recursive, advanced, pcre

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

자기 자신 매칭하는 패턴

재귀가 패턴이 자기 자신 참조 가능. 고전 사용: 임의 깊이 균형 잡힌 대괄호 매칭, 순수 정규식 (정규 언어) 못 함. 재귀 있으면 정규식이 context-free grammar 영역으로 확장.

문법

  • (?R) — 전체 패턴 재귀
  • (?N) — group N 재귀
  • (?P>name) 또는 (?&name) — named 그룹 재귀

균형 잡힌 대괄호 예시

\((?:[^()]++|(?R))*\)

읽기: 여는 괄호, 그 다음 (비-괄호 글자 OR 재귀 괄호 쌍) 어떤 수, 그 다음 닫는 괄호. (?R) 가 전체 패턴 재귀, 그래서 어떤 깊이든 중첩 쌍 매칭.

엔진 지원

  • PCRE, PHP, Perl: Yes
  • Python regex third-party: Yes
  • Python re: No
  • JavaScript, .NET, Ruby, Java, Go: No

재귀가 가장 portable 하지 않은 기능 중 하나. 필요하면 PCRE 에 commit 됐거나 진짜 파서 써야.

경험칙

재귀 정규식 손 뻗으면 문제가 아마 파싱. 진짜 파서가 exotic 정규식 기능 없이 균형 구분자 깨끗히 처리. 코드엔 Python ast, JSON 엔 json, HTML 엔 html.parser, 커스텀 DSL 엔 손으로 쓴 토크나이저. 재귀 정규식 존재; 사용이 보통 도구 전환했어야 했음 의미.

Code

재귀 패턴 (PCRE / Python regex)·text
# PHP / PCRE 에서
preg_match('/\((?:[^()]++|(?R))*\)/', 'foo(bar(baz)qux)quux', $m)
# $m[0] = '(bar(baz)qux)'

# Python third-party 'regex' 모듈로
import regex
m = regex.search(r'\((?:[^()]++|(?R))*\)', 'foo(bar(baz)qux)quux')
print(m.group())  # '(bar(baz)qux)'

# Python 내장 're' — 재귀 미지원
# 손 파서 작성 필요

# 재귀 named 그룹
pattern = r'(?P<paren>\((?:[^()]++|(?P>paren))*\))'
m = regex.search(pattern, 'foo(bar(baz))')
print(m.group('paren'))

External links

Exercise

(PHP, PCRE-enabled grep, 또는 Python regex 모듈에서) 균형 잡힌 JSON 식 중괄호 매칭 패턴 작성 시도. 그 다음 json.loads 로 등가 작성. 어느 쪽이 엣지 케이스 (escape 따옴표, 중첩 객체, 에러) 를 본인이 생각 안 해도 처리하는지 인지.

Progress

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

댓글 0

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

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