Application of RegEx
정규표현식 응용: 일정한 형식 속 모든 숫자에 2 더하기
다음의 텍스트에서 모든 숫자에 +2를 하고 싶다면?
3,5-8,9,10,11-14,15-18,31-34,59-62,79-82,93-96,99-102,111-114,129-132,167-170,185-188,201-204,215-218,221-224,227-230,283-286,287-290,293-296
위의 숫자는 페이지를 나타냅니다. 하지만 착오가 생겨서 모든 페이지에 2를 더해야 한다면 어떻게 해야 할까요?
제가 생각해낸 해법은 다음과 같습니다.
txtpages <- "3,5-8,9,10,11-14,15-18,31-34,59-62,79-82,93-96,99-102,111-114,129-132,167-170,185-188,201-204,215-218,221-224,227-230,283-286,287-290,293-296"
library(stringr)
page <- unlist(str_extract_all(txtpages, "\\d+"))
page <- as.numeric(page)
page <- page + 2
sformat <- str_replace_all(txtpages, "\\d+", "%d")
arg <- append(list(sformat), as.list(page))
do.call(sprintf, arg)
## [1] "5,7-10,11,12,13-16,17-20,33-36,61-64,81-84,95-98,101-104,113-116,131-134,169-172,187-190,203-206,217-220,223-226,229-232,285-288,289-292,295-298"
숫자를 얻어내는 것은 어렵지 않습니다. 정규표현식 "\\d+"를 사용하면 되죠. 단지 숫자가 1개 이상 연속된 부분을 찾아내면 됩니다. 문제는 어떻게 각 페이지를 더하기 2를 한 후에 동일한 형식 속에 넣느냐는 것이죠.
동일한 형식 속에 숫자를 배치하는 것은 spritnf() 함수를 활용했습니다. sprintf() 함수의 포맷(형식) 문자열속에 숫자가 위치할 장소를 알려주면 됩니다. "%d"가 그 역할을 하죠.
sformat <- str_replace_all(txtpages, "\\d+", "%d")
위의 코드를 실행한 결과 sformat은 다음과 같습니다.
sformat
## [1] "%d,%d-%d,%d,%d,%d-%d,%d-%d,%d-%d,%d-%d,%d-%d,%d-%d,%d-%d,%d-%d,%d-%d,%d-%d,%d-%d,%d-%d,%d-%d,%d-%d,%d-%d,%d-%d,%d-%d,%d-%d"
숫자가 위치할 장소를 %d로 표현하고 있습니다.
마지막으로 sprintf()함수는 sprintf(fmt, ...)으로 %d에 대응하는 수 하나를 인자 하나로 받습니다. 이를 위해 수치 벡터 page를 리스트로 만들고, sformat을 함께 묶어 모든 인자를 리스트를 만들어서 do.call()을 하고 있습니다.
do.call()은 인자를 모두 리스트로 받아 함수에 적용합니다. 예를 들어 print(a,b,c)는 do.call(print, list(a,b,c))가 되는 것이죠.
append()는 두 리스트를 합치는 역할을 합니다. 사실 c()를 써도 됩니다. 책의 CRUD를 참조하세요.
Leave a comment