어플리케이션들을 만들다 보면 종종 단어 검색, 메일 주소 점검, XML 문서의 무결성 확인 등과 같은 복잡한 문자열 처리 기능이 필요한 경우가 있게 마련이다. 이런 때에 패턴 매칭(pattern matching)이 자주 사용된다. Perl과 sed, awk와 같은 언어들은 일치하는 텍스트를 검색하기 위해, 패턴을 정의하는 문자들과 정규표현식을 사용해 향상된 패턴 매칭 능력을 제공해 주고 있다. 자바에서 패턴 매칭을 사용하려면 StringTokenizer 클래스와 수많은 charAt, substring 메소드를 동원해야만 한다. 하지만 이런 방식은 종종 아주 복잡하고 지저분한 코드를 만들어내곤 한다.
하지만
모두
지금까지의
이야기일
뿐
Java 2 Platform, Standard Edition(J2SE)가 1.4로
넘어오면서
정규
표현식을
다룰
수
있는 java.util.regex라는
새로운
패키지가
추가되었다. 이제
자바에도
정규
표현식의
강력함을
맛볼
수
있는
메타
캐릭터들을
사용할
수
있게
되었다.
이번
글에서는
정규
표현식에
대해
간단히
설명하고, 아래의
과정에
따라 java.util.regex 패키지를
통해
정규
표현식을
활용하는
방법에
대해
자세히
설명하도록
하겠다.
l
단어
바꾸기
l
메일
주소
점검
l
파일에서
제어
문자
제거
l
파일
검색
정규표현식이란
여러
문자열들의
공통적인
특성을
기술하는
문자들의
패턴이다. java.util.regex 패키지를
보면
입력
데이터로부터
패턴을
찾고
수정할
수
있는
다양한
방법들이
제공됨을
확인할
수
있을
것이다.
\$ |
^ |
. |
* |
+ |
? |
[‘ |
‘] |
\. |
|
|
|
‘\’로
시작하는
문자열을
제외한
모든
문자들은
보통
문자를
의미한다.
특수
문자들은
물론
고유한
기능을
갖고
있다. 예를
들어 ‘.’ 의
경우
라인
종결
문자를
제외한
어떤
문자와도
대응될
수
있다. 따라서
정규표현식 ‘s.n’ 은 ‘sun’, ‘son’ 등과
같이 ‘s’ 로
시작하고 ‘n’ 으로
끝나는
세
자로
된
문자열
어떤
것이든
될
수
있다.
이와
같이
우리는
정규표현식에서
제공되는
여러
특수
문자들을
통해
줄의
시작
단어를
찾거나, 특정
범위의
문자
찾기, 대소문자
구별
없이
찾기, 정확히
일치하는
단어
찾기
등의
작업을
쉽게
처리할
수
있다.
java.util.regex 패키지에서
제공하는
정규표현식은 Perl 언어에서의
정규표현식
사용법과
같기
때문에 Perl에
익숙한
사용자라면
같은
문법을
그대로
자바에도
적용할
수
있다. 만약
정규표현식에
익숙하지
않다면
아래
표가
많은
도움이
될
것이다.
Construct |
Matches |
Characters |
|
X |
The character x |
\\ |
The backslash character |
\0n |
The character with octal value 0n (0 <= n <= 7) |
\0nn |
The character with octal value 0nn (0 <= n <= 7) |
\0mnn |
The character with octal value 0mnn (0 <= m <= 3, 0 <= n <= 7) |
\xhh |
The character with hexadecimal value 0xhh |
\uhhhh |
The character with hexadecimal value 0xhhhh |
\t |
The tab character ('\u0009') |
\n |
The newline (line feed) character
('\u000A') |
\r |
The carriage-return character ('\u000D') |
\f |
The form-feed character ('\u000C') |
\a |
The alert (bell) character ('\u0007') |
\e |
The escape character ('\u001B') |
\cx |
The control character
corresponding to x |
|
|
Character Classes |
|
[abc] |
a, b, or c (simple class) |
[^abc] |
Any character except a, b, or c (negation) |
[a-zA-Z] |
a through z or A through Z, inclusive (range) |
[a-z-[bc]] |
a through z, except for b and c: [ad-z] (subtraction) |
[a-z-[m-p]] |
a through z, except for m through p: [a-lq-z] |
[a-z-[^def]] |
d, e, or f |
|
|
Predefined Character Classes |
|
. |
Any character (may or may not
match line terminators) |
\d |
A digit: [0-9] |
\D |
A non-digit: [^0-9] |
\s |
A whitespace character: [ \t\n\x0B\f\r] |
\S |
A non-whitespace character: [^\s] |
\w |
A word character: [a-zA-Z_0-9] |
\W |
A non-word character: [^\w] |
보다
자세한
설명과
예제는 J2SE 1.4 API 문서의 java.util.regex.Pattern 을
참조하도록
하자.
클래스와
메소드
Pattern 클래스
Pattern 객체는 Perl 문법과
비슷한
형태로
정의된
정규표현식을
나타낸다.
문자열로
정의한
정규표현식은
사용되기
전에
반드시 Pattern 클래스의
인스턴스로
컴파일되어야
한다. 컴파일된
패턴은 Matcher 객체를
만드는
데
사용되며, Matcher 객체는
임의의
입력
문자열이
패턴에
부합되는
지
여부를
판가름하는
기능을
담당한다. 또한 Pattern 객체들은
비상태유지
객체들이기
때문에
여러
개의 Matcher 객체들이
공유할
수
있다.
다음은 Pattern 클래스의
주요
메소드들에
대한
설명이다.
static Pattern compile(String regex) : 주어진
정규표현식으로부터
패턴을
만들어낸다(이를 ‘컴파일
한다’고
표현한다).
static Matcher matcher (CharSequence input) :
입력
캐릭터
시퀀스에서
패턴을
찾는 Matcher 객체를
만든다.
String[] pattern() :
컴파일된
정규표현식을 String 형태로
반환한다.
String[] split(CharSequence input) : 주어진
입력
캐릭터
시퀀스를
패턴에
따라
분리한다.
/*
* split 메소드를
이용해
입력
시퀀스를
콤마(‘,’)와
공백
문자를
기준으로
* 나눈다.
*/
import
java.util.regex.*;
public class Splitter
{
public static void main(String[] args) throws Exception
{
// 한
개
이상의
연속된 ‘,’와
공백문자를
의미하는
패턴을
만든다.
Pattern p = Pattern.compile("[,{space}]+");
// 패턴에
따라
입력
문자열을
쪼갠다.
String[] result =
p.split("one,two, three four
, five");
for (int i=0; i<result.length; i++)
System.out.println(result[i]);
}
}
Matcher 클래스
Matcher 객체는
특정한
문자열이
주어진
패턴과
일치하는가를
알아보는데
이용된다. Matcher 클래스의
입력값으로는 CharSequence라는
새로운
인터페이스가
사용되는데
이를
통해
다양한
형태의
입력
데이터로부터
문자
단위의
매칭
기능을
지원
받을
수
있다. 기본적으로
제공되는 CharSequence 객체들은 CharBuffer, String, StringBuffer 클래스가
있다.
Matcher 객체는 Pattern 객체의 matcher 메소드를
통해
얻어진다. Matcher 객체가
일단
만들어지면
주로
세
가지
목적으로
사용된다.
l
주어진
문자열
전체가
특정
패턴과
일치하는
가를
판단(matches).
l
주어진
문자열이
특정
패턴으로
시작하는가를
판단(lookingAt).
l
주어진
문자열에서
특정
패턴을
찾아낸다(find).
이들
메소드는
성공
시 true를
실패
시 false 를
반환한다.
또한
특정
문자열을
찾아
새로운
문자열로
교체하는
기능도
제공된다.
appendRepalcement(StringBuffer sb,
String replacement) 메소드는
일치하는
패턴이
나타날
때까지의
모든
문자들을
버퍼(sb)로
옮기고
찾아진
문자열
대신
교체
문자열(replacement)로
채워
넣는다. 또한 appendTail(StringBuffer sb) 메소드는
캐릭터
시퀀스의
현재
위치
이후의
문자들을
버퍼(sb)에
복사해
넣는다. 다음
절에
나오는
예제
코드를
참고하도록
하자.
CharSequence 인터페이스
CharSequence 인터페이스는
다양한
형태의
캐릭터
시퀀스에
대해
일관적인
접근
방법을
제공하기
위해
새로
생겨났다. 기본적으로 String, StringBuffer, CharBuffer 클래스가
이를
구현하고
있으므로
적절한
것을
골라
사용하면
되며, 인터페이스가
간단하므로
필요하면
직접
이를
구현해
새로
하나
만들어도
된다.
Example Regex Scenarios
아래
코드는 J2SE 1.4 도큐먼트의
예제를
완성한
것이다.
/*
* 이
코드는 "One dog, two dogs in the yard." 라는
문자열을
* 표준
출력을
통해
출력한다.
*/
import
java.util.regex.*;
public class Replacement
{
public static void main(String[] args)
throws Exception {
// ‘cat’이라는
패턴
생성
Pattern p = Pattern.compile("cat");
// 입력
문자열과
함께
매쳐
클래스
생성
Matcher m = p.matcher("one cat,"
+
" two cats in the
yard");
StringBuffer sb
= new StringBuffer();
boolean result = m.find();
// 패턴과
일치하는
문자열을 ‘dog’으로
교체해가며
// 새로운
문자열을
만든다.
while(result) {
m.appendReplacement(sb, "dog");
result = m.find();
}
// 나머지
부분을
새로운
문자열
끝에
덫붙인다.
m.appendTail(sb);
System.out.println(sb.toString());
}
}
메일
주소
포맷
확인
다음
코드는
주어진
입력
시퀀스가
메일
주소
포맷인가를
판단한다. 이
코드는
가능한
모든
형태의
메일
주소를
확인하는
것은
아니니
필요하면
코드를
더
추가해
사용하자.
/*
* 메일
주소에서
잘못된
문자
검사
*/
public class EmailValidation {
public static void main(String[] args)
throws Exception
{
String input = "@sun.com";
//메일
주소가 ‘.’이나 ‘@’와
같은
잘못된
문자로
시작하는
지
확인
Pattern p = Pattern.compile("^\\.|^\\@");
Matcher m = p.matcher(input);
if (m.find())
System.err.println("Email addresses don't start"
+
" with dots or @
signs.");
//’www.’으로
시작하는
주소를
찾는다.
p = Pattern.compile("^www\\.");
m = p.matcher(input);
if (m.find())
{
System.out.println("Email addresses don't start"
+
" with \"www.\", only web pages
do.");
}
p = Pattern.compile("[^A-Za-z0-9\\.\\@_\\-~#]+");
m = p.matcher(input);
StringBuffer sb =
new StringBuffer();
boolean result = m.find();
boolean deletedIllegalChars = false;
while(result) {
deletedIllegalChars =
true;
m.appendReplacement(sb, "");
result = m.find();
}
m.appendTail(sb);
input = sb.toString();
if (deletedIllegalChars)
{
System.out.println("It contained incorrect characters"
+
" , such as spaces or
commas.");
}
}
}
파일에서
제어
문자
제거
/*
* 지정된
파일에서
제어
문제를
찾아
제거한다.
*/
import
java.util.regex.*;
import java.io.*;
public class Control
{
public static void main(String[] args)
throws Exception
{
//파일
객체
생성
File fin = new File("fileName1");
File fout = new
File("fileName2");
//입출력
스트림
생성
FileInputStream fis =
new FileInputStream(fin);
FileOutputStream fos =
new FileOutputStream(fout);
BufferedReader in = new BufferedReader (
new InputStreamReader(fis));
BufferedWriter out = new BufferedWriter (
new OutputStreamWriter(fos));
// 제어문자를
의미하는
패턴
생성
Pattern p = Pattern.compile("{cntrl}");
Matcher m = p.matcher("");
String aLine =
null;
while((aLine = in.readLine()) != null) {
m.reset(aLine);
//제어
문자들을
빈
문자열로
대체
String result = m.replaceAll("");
out.write(result);
out.newLine();
}
in.close();
out.close();
}
}
파일
검색
/*
* .java 파일에서
주석을
찾아
출력한다.
*/
import
java.util.regex.*;
import java.io.*;
import java.nio.*;
import java.nio.charset.*;
import java.nio.channels.*;
public class CharBufferExample {
public static void main(String[] args) throws Exception
{
// 주석을
나타내는
패턴
생성
Pattern p =
Pattern.compile("//.*$", Pattern.MULTILINE);
// 소스파일
File f = new File("Replacement.java");
FileInputStream fis = new FileInputStream(f);
FileChannel fc
= fis.getChannel();
// 소스
파일로부터 CharBuffer 생성
ByteBuffer bb =
fc.map(FileChannel.MAP_RO, 0,
(int)fc.size());
Charset cs =
Charset.forName("8859_1");
CharsetDecoder cd = cs.newDecoder();
CharBuffer cb =
cd.decode(bb);
// 매칭
작업
수행
Matcher m = p.matcher(cb);
while (m.find())
System.out.println("Found comment: "+m.group());
}
}
이제 자바의 패턴 매칭 능력은 다른 언어 부럽지 않은 수준까지 다다르게 되었다. 정규 표현식은 데이터베이스 또는 다른 어플리케이션에 데이터를 넘기기 전에 그 데이터가 정확한 포맷을 지키고 있는 지 검증할 때, 또는 다양한 목적의 관리 작업에 사용될 수 있을 것이다. 간단히 말해 패턴 매칭이 필요한 모든 자바 프로그램에서 이제 정규표현식을 사용할 수 있게 되었다.
'2_ 바삭바삭 프로그래밍 > Java' 카테고리의 다른 글
Android - 어플리케이션 개발 시작하기. SDK 설치 및 실행 (0) | 2011.02.16 |
---|---|
Java - StringBuffer 문자열 위치 구하기 (0) | 2011.01.20 |
Java - 자바의 의미와 유래는? (0) | 2011.01.18 |
Java - 문자열 정리 (0) | 2011.01.17 |
Java - 자바기본 (0) | 2011.01.06 |