실제 텍스트를 파싱하려면 흔히 하나의 정규식으로 H1이나 (AH2b+EUH3) 같은 코드로 이루어진 구조적 항목을 인식하고 그 뒤에 오는 메시지를 캡처해야 한다. 한 줄로 쓰면 그 패턴은 빽빽한 구두점의 벽이 되었다. 중첩된 그룹, 전방 탐색, 수량자가 주석을 넣을 여지도 없이 늘어서고, 변경할 때마다 문자열 전체를 풀어헤쳐야 했다. 뻔한 해결책에는 각각 비용이 따랐다. 한 줄짜리를 유지하면 모든 수정이 위험해지고, 상세 모드를 직접 작성하면 같은 하위 패턴이 나타날 때마다 중복되며, 정규식 생성 라이브러리를 추가하면 새 문법을 배우고 의존성까지 떠안게 된다.

취한 방법은 패턴을 코드로 취급하는 것이었다. 작성자는 각 논리 단위를 한 번씩 정의했다. [A-Z]*H 같은 코드 조각, 더하기 기호로 구분된 코드를 감싸는 멀티코드, 그리고 전체 매처를 각각 모든 줄에 주석이 달린 원시 상세 모드 문자열로 정의하고, {code} 자리 표시자를 통해 더 작은 패턴에서 더 큰 패턴을 조합했다. re.VERBOSE는 공백과 해시 주석을 무시하므로 각 조각은 위에서 아래로 읽힌다. 괄호와 선택지가 글리프 수프가 아니라 눈에 보이는 구조가 된다. f-string은 빌드 시점에 해석되므로 re 모듈에 도달하는 것은 여전히 하나의 평범한 패턴 문자열이다.

효과는 한 줄 정규식이 아픈 바로 그 지점에서 나타난다. 각 조각이 한 번만 정의되므로 문법이 바뀌면 그것을 포함하는 모든 패턴이 갱신된다. 조각들은 결합되기 전에 re.findall로 단독 테스트할 수 있다. 그리고 스택에 새로 들어온 것은 없다. 작성자는 오래 공존해 온 표준 라이브러리 기능 두 가지를 사용했으며, 그 조합을 알아보는 데 3년이 걸렸다고 인정한다. 글은 함정도 기록한다. 해시와 공백은 이스케이프하거나 문자 클래스를 써야 하고, 중괄호 수량자는 f-string 안에서 두 번 써야 하며, 인라인 (?x) 플래그는 호출자가 플래그를 제어할 때도 상세 모드가 작동하게 유지한다.

정규식을 코드처럼 구조화한다. 각 조각을 주석이 달린 상세 모드 문자열로 한 번씩 정의하고 f-string으로 최종 패턴을 조합한다

re.VERBOSE는 이미 공백과 주석을 무시하므로 각 조각은 표준 라이브러리만 사용해 문서화된 코드처럼 읽힌다.

f-string 보간은 빌드 시점에 조각을 이어 붙여, 어떤 re 호출이든 변경 없이 받아들이는 평범한 패턴 문자열을 남긴다.

각 조각이 한 번만 정의되므로 문법이 바뀌면 반복된 인라인 복사본 대신 조합된 모든 패턴이 갱신된다.

조각들은 조합 전에 단독으로 테스트할 수 있어 실패가 조각 사이의 연결 지점으로 국소화된다.

의존성이 없고 새로운 DSL도 없으므로 이 접근은 설정 없이 어떤 Python 3.6+ 코드베이스에도 적용된다.

하나의 패턴이 유지보수를 거부할 때는 라이브러리를 추가하지 말고, 이미 가진 기능을 결합하라. 가독성을 위한 상세 모드 주석, 재사용을 위한 보간을 의존성 없이 함께 쓰는 것이다.

2022년 5월에 게시되어 Hacker News에서 304점과 90개의 댓글을 얻었다. 반응은 이 글을 계시로 받아들이는 쪽과 정규식을 재사용 가능한 하위 패턴으로 나누는 것이 이미 흔한 관행이었다고 지적하는 쪽으로 갈렸다. 댓글 작성자들은 보간 없이 재사용하기 위한 더 강력한 메커니즘으로 PCRE와 Perl의 DEFINE 서브루틴 블록, 그리고 서드파티 regex 모듈을 지목했고, 작성자는 DEFINE으로 같은 파서를 작성한 보너스 섹션을 덧붙였다. 글은 그런 단서들이 기록된 채로, 그리고 핵심 주장 — 의존성 없는 조합 가능한 주석 달린 패턴 — 은 그대로인 채로 남아 있다.

근거 확인하기

출처

  1. The unreasonable effectiveness of f-strings and re.VERBOSE death.andgravity.com · death.andgravity.com
  2. The unreasonable effectiveness of f-strings and re.verbose — Hacker News discussion Hacker News · news.ycombinator.com ·