본문 바로가기
Programing/Java

Java에서 정규표현식은 이렇게 사용하자

by Tomining 2015. 3. 12.
#1  같은 정규표현식을 반복해서 사용할 것이라면 Pattern 객체를 재사용하자.

해당 문자열이 정규표현식에 매칭되는지 확인하기 위해서 String클래스의 matches 메소드나 Pattern클래스의 matches 메소드를 사용하는 경우가 있는데요.

<String#matches>


<Pattern.matches> 


위 코드에서 보시다시피 두 메소드 모두 내부에서 정규표현식을 컴파일하여 Pattern객체를 생성하게 됩니다. Pattern 객체는 재사용가능하고 multi-thread 환경에서 사용할 수 있는 객체이기 때문에 같은 정규표현식에 대해 반복적인 매칭 여부를 확인하는 작업을 할 경우에는 Pattern객체를 static 변수로 사용하거나 직접 생성하여 재사용하도록 하는 것이 이점이 있습니다.

따라서, 다음과 같은 코드가 있다고 할 때,


다음과 같이 작성하는 것이 성능 상 이점이 있습니다.

#2  정규표현식에 조금 더 자세한 정보를 제공하자.

정규표현식 연산이 빠르게 수행될 수 있도록 조금 더 자세한 정보를 정규표현식에 기술하는 것이 좋습니다.
예를 들어, .*aaa.* 라는 정규표현식이 있는데 .{10}aaa.* 라고도 쓸 수 있다면 11번 째 자리에 a가 없으면 바로 fail이라는 것을 알 수 있기 때문에 빠르게 연산을 수행할 수 있습니다. 정규표현식 컴파일 시 내부적으로 최적화가 이루어진다고 합니다.

#3  .*hello.* 와 같은 정규표현식으로 매칭 여부 판단하기 보다는 String.indexOf("hello")를 사용하자.

indexOf 메소드가 일치하는 부분이 없으면 -1을 반환하므로 정규표현식 대신 indexOf를 활용할 수 있습니다.

#4  +, * 사용시 탐욕적수량자 대신 게으른수량자를 사용할 수 있으면 사용하자.

 기본적으로 +, *는 탐욕적수량자이고 가장 크게 일치하는 부분을 찾으려하기 때문에 게으른수량자(*?, +?)를 사용하는 것이 가능한 상황이라면, 사용하는 것이 성능상 더 낫다고 합니다. 탐욕적수량자의 경우 최초 일치하는 부분을 찾더라도 최대 매칭 덩어리를 찾기위해 계속 진행하기 때문입니다.

예를 들어, 특정 도메인이 네이버 서비스 도메인인지 확인하기 위해 다음과 같은 정규표현식을 작성했다고 할 때,

.+\.naver\.com

service.naver.naver.com 와 같은 도메인도 매칭이라고 볼 것이 아니라면 굳이 탐욕적수량자를 사용할 필요는 없을 것입니다. 
다음과 같이 게으른수량자를 사용하는 것이 성능상 이점이 있을 것입니다.

.+?\.naver\.com

#5  group내의 내용을 추출하거나 치환할 필요가 없다면 non-capturing group을 사용하는게 조금 더 빠르다.

정규표현식 사용 시 () 를 사용해서 group을 지을 수 있는데요. ()를 사용하여 group으로 묶을 경우 capturing group이라 하여 그룹 내용만을 가져오거나 치환하기위해 group 매칭 정보를 저장하게 됩니다.

하지만 group내 내용을 추출하거나 치환할 필요가 없다면 non-capturing group인 (?:) 을 사용하는 것이 성능상 조금 낫다고 합니다.