정규식은 개발 업무를 하는 데 있어서 가장 많이 사용되는 부분 중 하나입니다. 인프라를 구성하면서 설정 파일을 만들던, Backend server개발을 하면서 특정 요청들에 대해서 처리를 하던, UI에서 validation 처리를 하던 아주 많이 사용되는 기술 중 하나입니다. 여기서는 이러한 정규식을 Java에서 사용하는 것에 대해서 이야기하지만, 환경만 달라질 뿐 정규식 자체의 의미는 동일하므로 잘 활용하면 될 것 같습니다.

출처에 있는 정보와 조금 상이하게 동작하는 점이 있어 정리합니다. Java1.8 에서 확인된 내용임을 밝힙니다.

여기서는 Java 의 Pattern 객체와 Matcher 객체를 이용한 정규식 사용을 기본 방법으로 사용합니다. 다음 예시와 같은 소스코드를 주로 사용하였으며, 아래 GitHub 링크를 따라가면 예시 파일이 있습니다.

Pattern pattern = Pattern.compile(":");
Matcher matcher = pattern.matcher("T:EST");
System.out.println(matcher.find());

true

Download Sample code from GitHub

전방탐색 vs. 후방탐색

전방 탐색은 앞에서부터 후방 탐색은 뒤에서부터 특정 문자열을 찾는 방법입니다. 여러가지 방법을 이용할 수 있으나, 여기서는 정규식(regular expression)을 이용한 방법을 설명합니다 ‘전방’, ‘후방’ 이라는 말 자체가 너무 한자스러워서.. 적당한 다른 단어를 찾아보고 싶은데 못찾고 있습니다. 혹시 아시는 분 있으면 댓글좀 부탁드립니다…

전방탐색

우선 앞에서부터 문자열을 찾는 방법입니다(가장 일반적인 방법이기도 합니다). 정규식의 .+ 를 이용하여 ‘문자열이 시작하여.. 어떤 문자가 없거나 있다가..’ 라는 의미의 정규식을 넣어줍니다.

다음과 같은 문자열을 예로 들어 보겠습니다. 흔하게 볼 수 있는 URL 형태의 문자열입니다.

"http://www.linkeverything.com"
"https://mail.linkeverything.com"
"ftp://ftp.linkeverything.com"

여기에 다음과 같이 .+(:) 이라는 문자를 넣어서 정규식을 넣었다고 가정합니다.

.+(:)

이를 분석하면 앞에서 부터 시작하여 0개 이상의 문자열이 있다가, : 가 나타나는 순간까지의 문자열을 반환하는 것입니다.

java를 이용하여 위 예시 문자열에 match 함수를 이용하여 찾으면 다음과 같은 결과를 보입니다.

http:
https:
ftp:

만약, 기준이 되는 문자열을 제외한 검색을 하고 싶다면, 다음과 같이 =? 를 포함하면 됩니다.

첫 번째 예시처럼 :를 포함하여 반환하는 경우를 소비한다(consume)라고 표현합니다.

.+(=?:)

결과:

http
https
ftp

후방탐색

전방탐색과 반대의 경우로서, 뒤에서부터 문자열을 찾아갑니다. 사용하는 문자열은 ?<= 이며 뒤에서부터 탐색합니다.

예시 문자열:

ABC01: $23.45
HGG42: $5.31
CFMX1: $899.00
XTC99: $69.96
Total items found: 4
(?<=\$)[0-9.]+

위에서부터 탐색하며, $ 문자열로 시작하여 뒤에 0 ~ 9점(.)이 여러 개 나오는 것을 찾아 반환합니다.

결과:

23.45
5.31
899.00
69.96

응용하기

위 사항들을 이제 실제에 응용해 보겠습니다.

json 파일이 xml 형태보다 나은 점을 여러가지로 이야기합니다. 그 중에서 동일한 내용을 입력하는 데 있어서 단순히 용량을 덜 차지하게 된다는 장점도 있습니다. xml 파일의 경우에는 열고 닫는 태그가 존재해야 문법상 오류가 발생하지 않으며, 따라서 하나의 키 값에 대해서 열고 닫는 태그로 2번의 용량을 차지하게 됩니다.

xml 파일의 단점 중 하나가 parsing 하기가 힘들다는 점입니다. json 은 :을 중심으로 하여 좌측이 key, 우측이 value 라고 가정해도 무방합니다. key-value 쌍은 콤마(,)로 구분하기 때문에 조금 더 편리하게 parsing 할 수 있습니다.

다음의 xml 파일을 예로 들어 보겠습니다.

<HEAD>
<TITLE>Simplify linkeverything</TITLE>
</HEAD>

만약 위와 같은 파일에서 title 부분만 추출해서 내용을 가져오고 싶은 경우, 다음의 정규식을 활용합니다.

(?<=\<[tT][iI][tT][lL][eE]\>).*(?=\<\/[tT][iI][tT][lL][eE]\>)

전방탐색과 후방탐색을 섞어서 사용해도 가능 하겠지만, 이 경우에서는 후방탐색만을 이용하여 앞 뒤의 TITLE 태그를 찾아냅니다. .* 로 아무 문자열이 온다는 점을 명시하고, 앞 뒤에 <TITLE>, </TITLE> 에 대해 후방 탐색합니다. 이렇게 하면 대소문자를 무시한, title 태그에 대한 문자열을 반환합니다.

결과 :

Simplify linkeverything

부정어 사용하기

정규식을 사용하다 보면 부정형 으로 찾아야 하는 경우가 발생합니다. 예를 들어, “숫자가 아닌 것들” 만 찾는다거나, “문자가 아닌” 것들만 찾게 되는 것이 가장 쉬운 예입니다.

부정의 사용은 앞서 설명한 전방탐색, 후방탐색에 대해서 = 대신 ! 를 사용하여 같지 않음 을 표현합니다.

종류 설명
(?=) 긍정형 전방탐색
(?!) 부정형 전방탐색
(?<=) 긍정형 후방탐색
(?<!) 부정형 후방탐색

다음 예문을 이용하여 간단하게 예제만 다루겠습니다. 정규식을 더 깊이있게 다루려면 여러 조건들을 잘 조합해서 사용하면 되므로 여기서는 간단하게만 다루고 넘어가겠습니다.

I paid $30 for 100 apples,
50 oranges, and 60 pears.
I saved $5 on this order.

위와 같은 문구가 있는 상태에서 금액, 즉 $ 가 있는 숫자를 찾는다면,

(?<=\$)\d+

이렇게 찾을 수 있고, 만약 금액이 아닌 것(여기서는 수량)을 찾는다면,

\b(?<!\$)\d+\b

와 같이 활용할 수 있습니다.

출처에 있는 자료와 거의 동일한 내용으로 작성하였습니다. 하지만, 처음 예제에서 consume 여부가 Java 1.8 환경에서 다소 상이하여 다시 정리하였습니다. 원본은 아래 출처를 확인하시면 됩니다.

또한 Java 에서 정규식을 이용하는 경우, Pattern, Matcher 객체를 활용하게 되는데 이에 대한 예제도 함께 포함하고 있으니, 참고가 되시면 좋겠습니다. (맨 위 GitHub 링크 참고)

참고자료 및 출처


Leave a comment