유지 보수가 편한 정규표현식
정규표현식의 유지/보수
WOL
컴퓨터 과학의 농담조 용어로 WOL(Write Only Language)란 말이 있다. 우리나라 말로 번역한다면 “수정 불가 언어” 정도 되지 않을까? 프로그래밍 언어가 작성할 때에는 크게 무리가 없지만, 읽거나 수정을 하려고 하면 쉽게 읽기도 어렵고, 수정할 때에는 실수를 연달하게 되는 언어를 칭하는 말이다.
사실 정규표현식도 작성하기엔 크게 무리가 없어도 읽거나 수정하기에는 까다롭다. 예를 들어 정규표현식의 마지막 문자가 |
일 때 이를 탈출시키지 않으면 모든 문자열에 대해 TRUE
가 된다. 그런데 이런 오류를 발견하려면 앞의 모든 부분에 대해 검증을 거쳐야만 한다(정규표현식이 조금만 길어지면 그 발견 과정은 지루하고 멸렬하다.[1]).
[1]: 지리멸렬의 오타가 아님을 분명히 해두고 싶다.
유지 보수를 위한 제안
PCRE의 extended 모드
PCRE(perl=TRUE
)의 확장(extended) 모드를 사용하면 정규표현식을 읽기 쉽게 만들 수 있다. 확장 모드를 사용하려면 정규표현식의 처음에 (?x)
를 넣어준다. 확장 모드는 정규표현식 안의 공란을 무시한다. (만약 문자 그대로의 공란을 쓰려면 탈출시켜야 한다. 예. 스페이스='\\ '
, CR='\\\r'
하지만 []
안에서는 탈출시키지 않아도 된다.)
그리고 #
를 활용해서 주석을 넣어주면 읽는데 더욱 도움이 된다.
s <- c('2011-01-04', '2099/03/01', '1999.3.2', '2011 01 04',
'20110102')
grep(
'(?x)# Match a 20th or 21st century date in yyyy-mm-dd format
(19|20)\\d\\d # year (group 1)
[- /.] # separator
(0[1-9]|1[012]) # month (group 2)
[- /.] # separator
(0[1-9]|[12][0-9]|3[01]) # day (group 3)',
s,
perl=TRUE)
grep(
'(19|20)\\d\\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])',
s,
perl=TRUE)
## [1] 1 2 4 ## [1] 1 2 4
만약 확장 모드 없이 주석을 쓰려면 (?#...)
을 쓴다.
grep('(?#place)(abyss|heave)',
c('abyss', 'heaven', 'earth'))
## [1] 1 2
grep('(?#place)(abyss|heaven)(?#punctuation)[.!]',
c('abyss', 'heaven', 'earth',
'abyss.', 'heaven!', 'earth!'), perl=TRUE)
## [1] 4 5
패키지 rex
rex
패키지의 함수 rex
를 통해 정규표현식을 만들면 만들어진 정규표현식의 의미를 쉽게 알 수 있다. 다음은 Statistical Data Cleaning with R의 예를 그대로 옮겼다.
library(rex)
r <- rex(blank,
one_or_more(digit),
maybe("." %or% ",", one_or_more(digit)),
maybe(one_of("e", "E"), one_or_more(digit)),
blank)
cat("다음의 정규표현식과 위의 rex 함수를 비교해보자.\n")
cat(r, "\r\n")
cat("rex 결과를 활용한 정규표현식 함수\n")
grep(r, c(" 1.23 ", " 23e+17 ", " 10e2 ", "11.23e1.22"))
## 다음의 정규표현식과 위의 rex 함수를 비교해보자. ## [[:blank:]](?:[[:digit:]])+(?:(?:\.|,)(?:[[:digit:]])+)?(?:[eE](?:[[:digit:]])+)?[[:blank:]] ## rex 결과를 활용한 정규표현식 함수 ## [1] 1 3
위에서 (?:
, )
는 non-capturing group으로 \1
등으로 나중에 사용되지 않는 부분을 나타내기 위해서 사용한다.
rex
를 통해 정규표현식을 산출하는 가장 기본적인 방법은 다음의 도움말로 확인할 수 있다.
?rex::character_class
?rex::counts
?rex::`%or%`
?rex::group
?rex::capture
아쉬운 점은 기존의 정규표현식을 읽기 쉽게 변환해 주지는 않는다는 점이다.[2]
[2]: REGEXPER 또는 Debuggex와 같은 사이트에서는 주어진 정규표현식을 시각화해주긴 하지만, 정규표현식의 종류를 유의해야 한다.
Leave a comment