개인적인 정리가 필요해서 시작했고, 지금도 그것이 중요한 이유이지만, 간혹 드물게 접속해서 보시는 분들이 있는 것 같습니다.
제가 검색등을 통해서 도움을 받았듯, 혹시라도 조금이라도 도움이 될 수 있다면 좋겠다는 생각을 아주 가끔(^^)은 하게 되었습니다.
조금은 생각을 정리해서 기재 해야 겠다는 생각이 들기 시작하는 중입니다.
정규식은 Java 아닌 다른 곳에서도 많이 사용되는 표현 형식입니다.
문장중의 특정 단어를 찾거나, 일부분을 변경하는 것 등에서도 많이 사용됩니다. Linux 등의 환경에서는 일반정규식은 말할 것도 없고, 정규식이라 말하긴 어려워도 검색(파일 및 내용)을 위한 많은 명령어가 제공되기도 합니다. (awk, sed 등의 명령어는 정말 강력합니다. find 와 함께 쓰는 xargs 명령어도 파일 내용을 찾는 데에는 더할 나위 없이 강력하고요 ... ), Unix 에서의 egrep 는 정규식 사용할 수 있게 도와 줍니다.
java 에서는 java.util.regex package 정규식 관련한 내용이 담겨 있습니다.
처음 블로그 할 때 기록했던 수치 확인 내용을 다시 한번 기록해 보겠습니다.
[+\\-]?([\\d]+([.][\\d]*)?|[.][\\d]+)([eE][+\\-]?[\\d]+)?
숫자형으로 넘어온 데이터가 DB 에서 문자열로 가져올 때, 가끔 형변환된 문자열이 다음과 같이 출력되어 나타날 수가 있습니다. -.7265 -1.2E+12 등의 문자열에서 -.으로 -0.7.. 형식이 아닌 데이터가 나타날 때도 수치형 데이터 라고 인식 시켜 주려면 +,- 기호가 사용가능한
기호라는 표기가 필요합니다. 그게 [+\\-]? 기호 입니다. \\기호는 - 기호가 [] 블럭에서 이미 사용되고 있는 문자열이라서 의미 자체로 '-' 다 라는 것을 인식시켜 주기 위한 부분 입니다. '?' 는 있을 수도 있고 없을 수도 있다라는 의미로 받아 들이시면 됩니다.
정규식 API 를 참조하시면서 보시면 쉽게 확인 하실 수 있을 것 같습니다. 참고로 [\\d\\w]+ 라는 의미는 숫자 혹은 문자라는 의미 입니다.
그럼 위의 내용을 어떻게 사용할까요 ?
위의 내용은 굳이 Patten 객체까지 사용하지 않고 String 객체에서 직접 사용하 실 수 있습니다. 아래와 같은 간단한 코드 입니다.
public static boolean isNumberFormatStr(String str) {
if ( str == null ){
return false;
}
return str.matches("[+\\-]?([\\d]+([.][\\d]*)?|[.][\\d]+)([eE][+\\-]?[\\d]+)?");
}
다음의 코드를 살펴보겠습니다.
public static void testRegex() {
StringBuffer sb = new StringBuffer();
sb.append("<a href=\"www.google.co.kr\" \r\n target=\"_black\"> TEST </a><a onClick=www.naver.com> test2\r\n</a>");
System.out.println( sb );
Pattern pObj = Pattern.compile("(<[^>]*>)",Pattern.MULTILINE);
Matcher mObj = pObj.matcher(sb);
while ( mObj.find()) {
System.out.println (mObj.groupCount() + " : " + mObj.group(0));
}
pObj = Pattern.compile("(<(/)?([\\w]+)([\\s]+[^>]*)?>)",Pattern.MULTILINE);
mObj = pObj.matcher(sb);
while ( mObj.find()) {
int cnt = mObj.groupCount();
for ( int i = 1; i <= cnt; i++ ) {
System.out.print ("\t\t" + i + " : " + mObj.group(i));
}
}
}
html tag 를 확인하기 위한 코드 입니다.
처음에는 단순히 tag 만을 확인 하기 위해서 '<'가 있고 '>' 이 아닌 모든것인 있을 수도 있고 '>' 이 있는 유형을 찾도록 했습니다. <[^>]*> 가 그런 의미 입니다.
하지만 이렇게 되면 tag 안의 내용을 다시 확인하여야 합니다. 종료 tag인지 아닌지 이름이 뭔지 속성은 있는지 등등을요 그래서 (/)? 으로 종료 태그 여부를 확인합니다. 다시 태그 이름은 '<'다음에 붙어 나오는 단어이기 때문에 [\\w]+로 확인을 합니다.
그 다음은 속성에 해당하는 것이 있다면 확인하는 구문이 들어 있습니다.
()기호와 []기호 + ? * {1,5} 등의 기호로 찾아야할 영역을 지정할 수 있습니다.
아래의 내용을 한번 살펴 보겠습니다.
"ABCDEFGABCDEFGABCDEFG ABCDEFGABCDEFGABCDEFG" 라는 문장이 있습니다.
이 문장에서 EFG 가 포함된 영역과 그 외 영역을 찾고자 한다고 가정해 보겠습니다.
일반적으로 생각해 볼 수 있는 정규식은 (.+)(EFG)라는 문장을 생각해 볼 수 있습니다.
무엇이 되었던 EFG 앞의 내용은 다 그리고 EFG 를 찾아라 하는 구성입니다.
이것을 실행하면 ABCDEFGABCDEFGABCDEFG ABCDEFGABCDEFGABCD EFG 의 두 영역을 찾아 오게 됩니다. 원하는 내용이었다면 다행이지만 의도가 ABCD EFG 의 반복을 원하였다면 위의 정규식에서 (.+?)(EFG)의 구성으로 변경해 주시면 됩니다. +뒤의 ? 의 의미는 EFG 가 포함된 영역을 최소한의 수준에서 찾아 주게 됩니다.
API의 Greedy quantifiers, Reluctant quantifies 의 내용을 확인해 보시면 됩니다.
문장 전체에서 특정 영역을 찾아 오는 Parser를 구성할 때 위의 내용이 빈번하게 사용될 수 있습니다.(제 개인적으론 그렇습니다.)
코드로 구성해 보면 다음과 같습니다.
String str = "ABCDEFGABCDEFGABCDEFG ABCDEFGABCDEFGABCDEFG";
System.out.println ("\n\n" + str );
Pattern pObj = Pattern.compile("(.+?)(efg)",Pattern.CASE_INSENSITIVE);
Matcher mObj = pObj.matcher(str);
while ( mObj.find() ) {
System.out.println (mObj.group(1) + " : " + mObj.group(2) );
}
정규식은 mail 형식 html tag 수치확인 등의 단순한 확인 및 처리에서 부터 좀더 복잡한 파일내용의 분석 등 다양한 영역에서 사용할 수 있습니다. 정규식의 강력함을 접하면서 다 알지는 못하지만, 혹시 정규식을 많이 접하지 않았던 분들에게 조금이라도 도움이 될 까 해서 기록해 보았습니다.