TL;DR

  • re.match()는 문자열 시작 부분만 일치시키지만 동작이 모호해 Python 3.15에서 소프트 디프리케이션되며, 새 코드는 re.prefixmatch()를 선호하는 방향임
  • 소프트 디프리케이션은 기존 코드에서 API를 계속 안전하게 사용할 수 있지만 새 코드에서는 사용하지 않도록 문서로만 권고하는 방식임
  • re.search()는 문자열 어디서든 일치시키고, re.fullmatch()는 문자열 전체가 일치하는지 확인하는 함수임
  • re.prefixmatch()re.match()의 시작 부분 고정 동작을 명시적으로 표현하는 별칭이며 기존 match() 이름이 제거될 계획은 없음
  • RuffTID251 규칙으로 프로젝트에서 re.match() 사용을 탐지하고 re.fullmatch() 또는 re.search() 사용을 권고할 수 있음

소프트 디프리케이션

  • Python의 하위 호환성 정책인 PEP 387에서 2023년 소프트 디프리케이션이 도입됨.
  • 소프트 디프리케이션은 새 코드를 작성할 때 더 이상 사용하지 않아야 하지만 기존 코드에서 계속 사용해도 안전한 API에 적용하는 방식임.
  • 해당 API는 문서화와 테스트가 유지되지만 더 이상 개발되거나 기능이 개선되지 않음.
  • 소프트 디프리케이션은 향후 API 제거를 의미하지 않으며 경고도 발생시키지 않음.
  • 대체 API가 있다면 이를 제안하는 문서상의 사용 자제 권고에 해당함.
  • 소프트 디프리케이션을 향후 일반적인 하드 디프리케이션으로 전환할지는 별도의 결정 사항이며, 하드 디프리케이션에서는 제거가 뒤따를 수 있음.
  • 소프트 디프리케이션이 일반 디프리케이션이나 제거 단계로 자동 전환되는 것은 아님.

re.match()

  • re.match()는 정규 표현식이 문자열의 시작 부분에서 일치하는지 확인하는 함수임.
  • 정규 표현식 pi와 문자열 pi를 비교하면 처음부터 끝까지 pi가 일치함.
  • pipie를 비교해도 문자열 시작 부분의 pi가 일치함.
  • piapi를 비교하면 시작 부분이 a이므로 일치하지 않음.
  • pimagpie를 비교해도 시작 부분에 pi가 없어 일치하지 않음.
  • 따라서 re.match()는 문자열 시작 부분에만 고정되는 함수이며, 이 절반만 고정된 동작이 직관에 어긋날 수 있음.

re.search()

  • 문자열 시작 부분에 고정하지 않고 문자열 어디에서든 일치시키려면 re.search()를 사용함.
  • pipipie를 비교하면 모두 문자열 시작 위치에서 일치함.
  • piapi를 비교하면 위치 1~3에서 일치함.
  • pimagpie를 비교하면 위치 3~5에서 일치함.
  • re.search()는 기본적으로 시작 앵커와 끝 앵커를 사용하지 않는 방식임.

re.fullmatch()

  • 문자열의 시작과 끝을 모두 고정하고 전체 문자열이 일치하는지 확인하려면 re.fullmatch()를 사용함.
  • pipi를 비교하면 전체 문자열이 일치함.
  • piapi, pie, magpie를 비교하면 앞뒤에 다른 문자가 남아 전체 일치가 아니므로 일치하지 않음.

re.prefixmatch() 도입

  • re.match()의 예상하기 어려운 절반 고정 동작에 대응해 Python 3.15에서 re.prefixmatch()라는 새 별칭이 도입됨.
  • Python의 선(The Zen of Python)이 제시하는 “명시적인 것이 암시적인 것보다 낫다”는 원칙에 따라 prefixmatch()라는 이름이 의도된 동작을 더 분명하게 전달함.
  • match()라는 이름은 이 오래된 Python 특성을 이미 아는 사람이 아니라면 의도된 동작에 의문을 남길 수 있음.

re.match()의 소프트 디프리케이션

  • 더 명시적인 대체 함수가 추가되면서 Python 3.15에서 re.match()가 소프트 디프리케이션됨.
  • 30년 넘게 코드에서 사용된 기존 match() 이름을 제거할 계획은 없음.
  • 이전 Python 버전을 지원하는 코드는 계속 match()를 사용해야 하며, 새 코드는 prefixmatch()를 우선 사용해야 함.
  • 절반만 고정하는 동작이 정말 의도한 것이라면 re.prefixmatch()를 사용하고, 그렇지 않다면 re.search() 또는 re.fullmatch()를 사용함.

비교

  • re.search()는 시작 앵커와 끝 앵커를 사용하지 않으며 Python 1.5부터 제공됨.
  • 특수 문자를 사용하면 re.search("^pi", string) 또는 re.search(r"\\Api", string)처럼 시작 부분을 고정할 수 있음.
  • re.match()는 시작 앵커만 사용하고 끝 앵커는 사용하지 않으며 Python 1.5부터 제공됨.
  • 동등한 표현으로 re.search("^pi", string) 또는 re.search(r"\\Api", string)를 사용할 수 있음.
  • re.prefixmatch()는 시작 앵커만 사용하고 끝 앵커는 사용하지 않으며 Python 3.15부터 제공됨.
  • 동등한 표현으로 re.search("^pi", string) 또는 re.search(r"\\Api", string)를 사용할 수 있음.
  • re.fullmatch()는 시작 앵커와 끝 앵커를 모두 사용하며 Python 3.4부터 제공됨.
  • 동등한 표현으로 re.search("^pi$", string) 또는 re.search(r"\\Api\\z", string)를 사용할 수 있음.
  • 특수 문자를 사용하지 않는 함수 호출이 일반적으로 조금 더 빠름.

린트

  • 프로젝트에서 re.match() 사용을 피하려면 Ruff에서 TID251 규칙을 활성화할 수 있음.
  • TID251flake8-tidy-imports의 금지 API 규칙이며, re.match를 금지 대상으로 지정하고 re.fullmatch() 또는 re.search() 사용을 권고하는 메시지를 설정할 수 있음.
  • 별도 설정으로 Ruff를 실행할 때도 TID251re.match 금지 API 메시지를 지정할 수 있음.
  • 관련 내용으로 Seth Larson의 Python 정규 표현식 사용 권고인 “^…$가 아니라 \A…\z 사용”이 있음.

출처 및 이미지

  • 헤더 사진은 Hugo van Kemenade의 “Double-exposure bike and pedestrian stencils”이며 CC BY-NC-SA 2.0 라이선스임.