Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 3 Current »

캡쳐 그룹

Groovy의 매우 유용한 기능 중 하나는 정규식을 이용하여 데이터에서 특정 부분을 잡아내는 것입니다. 아래 데이터에서 각 요소를 뽑아내고 싶다고 가정해봅시다:

물론 String의 split() 메서드를 이용하여 잘라낸 후 Livepool과 England 사이의 ","를 제거하고, 나머지 조각들에 대해서도 비슷한 작업을 반복해주면 되긴 합니다. 하지만 정규식을 이용하면 이 작업을 한번에 끝낼 수 있습니다. 이 작업을 위한 문법은 약간 특이합니다. 우선 정규식을 작성하고 뽑아내고자 하는 부분을 괄호 안에 넣으세요:

다음으로는 =~ 연산자로 "matcher"를 정의해야 합니다:

이제 matcher 변수는 java.util.regex.Matcher 클래스의 인스턴스를 갖게 됩니다. 물론 Groovy에 의해 확장된 추가 기능도 함께 들어 있습니다. 자바 방식으로 Matcher 객체를 사용할 수도 있지만, 더 Groovy 적인 방법은 Matcher 객체를 마치 2차원 배열인 것 처럼 취급하는 것입니다. 2차원 배열이란 단순히 배열의 배열을 말합니다. 배열의 첫번째 차원에는 이 정규직에 의해 일치된 문자열들이 담깁니다. 이 예제에서는 정규식에 대해 전체 문자열이 단 한번 일치되었기 때문에 첫번째 차원의 길이는 1 입니다. 따라서 다음과 같이 쓰면:

다음과 같이 평가됩니다:

이제 두번째 차원을 이용하여 각 캡쳐 그룹에 접근할 수 있습니다:

정규식을 이용해서 얻을 수 있는 추가적인 장점은 주어진 데이터의 형식이 적합한지를 검사할 수 있다는 사실입니다. 즉, *locationData*의 내용이 "Could not find location data for Lima, Peru" 였다면 위 if 문 안의 블록은 실행되지 않을 것입니다.

비 캡쳐 그룹(Non-matching groups)

가끔, 괄호로 표현을 묶고 싶기는 한데 그 괄호가 캡쳐 그룹으로 사용되는 것은 원하지 않을 때가 있습니다. 이럴때는 괄호 바로 다음에 ?: 를 붙여주면 됩니다. 예를 들어 사람들의 이름 표기를 바꾸고 싶은데 중간 이름(middle name)은 무시하고자 한다면 아래와 같이 쓸 수 있습니다:

결과는 아래와 같습니다:

이렇게 하면 성(last name)이 항상 두번째 캡쳐 그룹에 잡히게 됩니다.

바꾸기

정규식의 단순하지만 정말 강력한 기능 중 하나는 문자열에서 특정 패턴을 찾아서 다른 문자열로 바꿔주는 기능입니다. java.util.regex.Matcher의 replaceFirst() 혹은 replaceAll() 메서드를 이용하면 됩니다.

예를 들어, J.K. Rowlings의 책인 Harry Potter 시리즈를 다른 이름으로 팔아먹기 위해 문자열 중에 나오는 모든 "Harry Potter"를 "Tanya Grotter"로 치환해봅시다. (정말 이짓을 한 사람이 있습니다. 못 믿겠으면 구글에서 찾아보세요):

위 예제에서는 두 번의 치환 작업을 수행했습니다. 한번은 전체 이름인 "Harry Potter"에 대해, 또 한번은 이름인 "Harry"에 대해서만.

릴럭턴트(reluctant) 연산자

?, + 그리고 * 연산자는 모두 기본적으로 그리디(greedy - 욕심많은) 입니다. 즉, 가능하면 많은 부분과 일치시키려는 특성이 있습니다. 하지만 가끔은 이런 특성을 원치 않을 때가 있습니다. 15세기 교황을 나열한 다음 예제를 살펴보겠습니다:

우선 이름(예를 들어 "Pope Anastasius II" 에서 "Anastasius")과 연도만 정확히 추출하는 정규식을 써보겠습니다:

Which splits up as:

/

Pope

(.*)

(?: .*)?

([0-9]+)

-

([0-9]+)

/

문장 시작

Pope

몇 개의 글자들을 잡아내고

비 캡쳐 그룹: 스페이스와 몇 개의 문자들

숫자를 잡아낸 후

-

다시 숫자

그리고 문장의 끝

위 정규식에서 우리는 첫번째 캡쳐 그럼이 교황의 이름을 잡아낼 것을 기대하지만 실제로는 그렇게 되지 않습니다. 너무 많이 잡아내고 있습니다. 예를 들어 첫번째 줄은 다음과 같이 나뉩니다:

/

Pope

(.*)

(?: .*)?

([0-9]+)

-

([0-9]+)

/

문장 시작

Pope

Anastasius I

 

399

-

401

문장 끝

첫번째 캡쳐 그룹이 너무 많은 입력을 잡아내고 있습니다. 우리가 원하는 건 "Anastasius"만 잡는 것입니다. 다시 말하면 첫번째 캡쳐 그룹은 가능한 최소한의 입력만 잡아내어야 합니다. 자바 정규식은 이런 경우에 대비하여 "reluctant" 버전의 *, +, ? 연산자를 제공합니다. 연산자 뒤에 ? 를 붙여서 *?, +?, ??와 같이 표기하면 됩니다. 다음은 이것을 적용한 새 정규식 입니다:

이제 가장 복잡해보이는 입력에 대해 정규식을 적용해봅시다:

/

Pope

(.*?)

(?: .*)?

([0-9]+)

-

([0-9]+)

/

문장 시작

Pope

Leo

I the Great

440

-

461

문장 끝

정확히 우리가 원하는 결과입니다.

다음 코드를 통해 위에서 설명한 내용들을 테스트할 수 있습니다:

수정하기 전의 정규식을 사용해서 위 예제를 다시 시도해보세요. 출력이 어떻게 깨지는지 살펴볼 수 있습니다.

  • No labels