“어디서나” 동작하는 정규 표현식
(johndcook.com)- 정규 표현식은 구현마다 지원 기능과 문법이 달라, 한 도구에서 통하던 패턴이 다른 환경에서는 실패하거나 수정이 필요할 수 있음
- Perl처럼 기능이 많은 환경에 익숙할수록 호환성 문제를 더 자주 만나며, 설치 권한이 없는 컴퓨터까지 고려하면 공통 부분집합을 쓰는 편이 안전함
- “어디서나”를 가장 엄격하게 정의하면 리터럴,
[…]문자 클래스,. * ^ $같은 기본 특수 문자만 남을 정도로 범위가 좁아짐 - GNU
sed,awk,grep에sed와grep의-E옵션을 함께 쓰면 활용 가능한 공통 기능이 넓어지지만, 이 조합에서는awk가 대체로 최소 공통분모가 됨 - Emacs는
+? ( ) { } |에 백슬래시가 필요하고\s,\S의 의미도 달라, 같은 정규 표현식을 여러 도구에 쓰려면 예외 문법까지 확인해야 함
정규 표현식 호환성이 어려운 이유
- 정규 표현식의 가장 큰 불편은 구현별 차이에서 나옴
- 어떤 도구에서 지원되는 기능이 다른 도구에서는 아예 없을 수 있음
- 같은 기능이라도 문법이 조금씩 다를 수 있음
- Perl은 기능이 많은 정규 표현식 환경이라, Perl 기준으로 당연해 보이는 기능이 다른 환경에서는 빠져 있을 때가 있음
- 다른 도구의 Perl 유사 대체품을 쓰는 방법도 있지만 표준적이지 않아, 동료나 고객에게 바로 실행되는 코드를 보내기 어려워짐
- 소프트웨어를 설치할 수 없는 컴퓨터에서 작업해야 하는 상황까지 고려하면, 여러 환경에서 동작하는 정규 표현식 기능의 부분집합을 찾는 접근이 필요함
- “어디서나”의 정의를 엄격하게 잡을수록 사용할 수 있는 기능은 줄어듦
- 리터럴
[…]문자 클래스. * ^ $특수 문자
sed, awk, grep, Emacs에서의 공통 범위
- 대상 도구를
sed,awk,grep, Emacs로 좁히면 “어디서나”의 기준을 조금 느슨하게 잡을 수 있음 - GNU 버전의
sed,awk,grep을 쓰고sed와grep에-E옵션을 적용하면 공통 기능 목록이 넓어짐- 세 도구의 정규 표현식 기능은 비슷함
awk기능은 다른 도구에서도 대체로 지원됨- 예외적으로 단어 경계는
awk에서\<,\>를 쓰며,\b,\B와 다름
- Emacs는
awk기능 대부분에 대응하지만 문법 차이가 있음+ ? ( ) { } |가awk와 같은 역할을 하려면 앞에 백슬래시가 필요함awk의\s,\S에 해당하는 표현은 Emacs에서\s-,\S-임
- Emacs에서
\s,\S는 공백/비공백이 아니라 문자 클래스를 시작함-클래스는 공백을 뜻함\s.는 구두점 문자\S.는 비구두점 문자
- 이 기준에서 사용할 수 있는 기능은 다음과 같음
.^,$[…],[^…]*\w,\W,\s,\S\1부터\9까지의 역참조\b,\B?,+|대안{n,m}반복 횟수(...)캡처
- 단,
gawk는 치환 문자열에서는 역참조를 지원하지만 정규 표현식 자체에서는 역참조를 지원하지 않음 look-around는 고급 기능으로 볼 수 있고,\d는 숫자에 대한 기본 기능처럼 보일 수 있지만 많은 정규 표현식 변형에서 지원되지 않음
댓글과 토론
Hacker News 의견들
-
Emacs에서는 무엇을 이스케이프해야 하는지 거의 찍어 맞히는 느낌이라 특히 고생함
rx라는 대안도 있긴 하지만[0], 실제로 쓰기 즐겁지는 않음
정규식 문법 자체를 넘어서, 실제 사용 단계에서도 인코딩·이스케이프 문제가 자주 생김
셸에서 정규식을 입력하면 제대로 이스케이프해야 하고, Python에서는 원시 문자열(raw string)인지 확인해야 하는 식임
그래도 대부분의 도구에서 정규식을 쓰는 방식이 어느 정도 비슷한 범위 안에 들어온 건 현대의 기적에 가까움
[0]: https://www.gnu.org/software/emacs/manual/html_node/elisp/Rx...- 정규식이 들어간 셸 스크립트를 생성하는 Python을 작성하면 더 재미있어짐
서로 다른 이스케이프 규칙이 중첩되는 상황이 계속 생김 - 억지로 장점을 찾자면, 검색 대상이 Elisp 코드일 때
(와)가 문자 그대로 매치되는 건 살짝 편리함 - 정규식은 여러 DSL의 잡탕이 아니라 구조화된 언어였어야 함
- 정규식이 들어간 셸 스크립트를 생성하는 Python을 작성하면 더 재미있어짐
-
글쓴이는 거의 도달할 듯 말 듯하지만, 결국 POSIX 기본 정규식은 어디서나 동작한다고 말하려는 것 같음
다만 Single Unix Specification 8판을 모두가 따라잡은 건 아니고, 그 판에서 BRE가 조금 바뀌었다는 단서가 붙음- 그 평가는 글쓴이에게 공정하지 않아 보임
그런 단서가 없었다면 애초에 그 글을 쓸 필요도 없었을 것임
- 그 평가는 글쓴이에게 공정하지 않아 보임
-
예전에 탐욕적 의미론과 leftmost maximal 의미론 양쪽에서 같은 방식으로 매치되는 정규식을 찾는 논문을 쓴 적이 있음
https://par.nsf.gov/servlets/purl/10534654 -
어떤 도구가 어떤 정규식 언어를 받는지, 그리고 임의의 부분 문자열·접두사·접미사·전체 문자열·한 줄·줄 안의 부분 문자열 중 무엇을 매치하는지 명확히 해야 한다고 늘 까다롭게 봐왔음
여기에는 [더 널리 쓰이는 것들][1]이 있고, 그 밖에 PCRE와 Python도 있음
grep 같은 곳에서 보이는 오래된 형식 일부가 [POSIX에 명세되어 있다][2]는 걸 배우는 데 시간이 좀 걸렸음
[1]: https://cppreference.com/cpp/regex#Regular_expression_gramma...
[2]: https://pubs.opengroup.org/onlinepubs/009696899/basedefs/xbd... -
Russ Cox의 정규식 페이지를 공유하고 싶음
읽을 만한 좋은 자료라고 봄
https://swtch.com/~rsc/regexp/ -
이런 이유 때문에 RFC 9485인 I-Regexp: An Interoperable Regular Expression Format이 중요함
https://datatracker.ietf.org/doc/html/rfc9485 -
Go 표준 라이브러리의 regexp 패키지는 RE2 엔진을 쓰기 때문에 역참조를 지원하지 않음
치환에서는 쓸 수 있지만 매칭에서는 안 됨regexp는 re2를 쓰는 게 아니라, 같은 개념을 별도로 구현한 것임
-
규칙 엔진, 템플릿 엔진, IFTTT류 엔진에서 비슷한 좌절을 겪고 나서 JSONLogic용 Rust 라이브러리를 만들었고, 다른 언어용 바인딩도 사용함
https://github.com/GoPlasmatic/datalogic-rs -
JSON Schema 문서에도 권장하는 정규식 부분집합이 있음
https://json-schema.org/understanding-json-schema/reference/...