자바 API에 있는 java.util.regex 패키지의 Pattern 클래스를 보면 정규식을 표현하는 Construct가 나와 있다.
http://java.sun.com/javase/6/docs/api/java/util/regex/Pattern.html

아래 내용은 Java JDK에 있는 내용을 재 정리 한것이다. (시간이 되면 번역을 할까 생각중인데, 궂이 그럴필요가...)

가장 먼저 특수 문자에 대해서 알아보자. 각각의 8진수, 16진수, tab, 이스케이프 문자등을 나타내기 위해서는 다음과 같이 사용하면 된다.

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

그 다음에는 문자를 표현하는 방식을 보자. 특정 범위의 문자나 범위 이외의 문자는 다음과 같이 표시한다.

[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-d[m-p]] a through d, or m through p: [a-dm-p] (union)
[a-z&&[def]] d, e, or f (intersection)
[a-z&&[^bc]] a through z, except for b and c: [ad-z] (subtraction)
[a-z&&[^m-p]] a through z, and not m through p: [a-lq-z](subtraction)

위의  방식을 사용하여 정의할 수도 있겠지만, 다음과 같이 미리 정의된 문자열을 사용하면 보다 편하게 사용 가능하다.

. 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]

그리고, POSIX 문자열을 사용할 경우에는 다음과 같이 정의할 수 있다.
(참고로 POSIX가 뭔지 모르시는 분은 http://ko.wikipedia.org/wiki/POSIX 를 참조하시면 쉽게 이해 될것이다.)

\p{Lower} A lower-case alphabetic character: [a-z]
\p{Upper} An upper-case alphabetic character:[A-Z]
\p{ASCII} All ASCII:[\x00-\x7F]
\p{Alpha} An alphabetic character:[\p{Lower}\p{Upper}]
\p{Digit} A decimal digit: [0-9]
\p{Alnum} An alphanumeric character:[\p{Alpha}\p{Digit}]
\p{Punct} Punctuation: One of !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
\p{Graph} A visible character: [\p{Alnum}\p{Punct}]
\p{Print} A printable character: [\p{Graph}\x20]
\p{Blank} A space or a tab: [ \t]
\p{Cntrl} A control character: [\x00-\x1F\x7F]
\p{XDigit} A hexadecimal digit: [0-9a-fA-F]
\p{Space} A whitespace character: [ \t\n\x0B\f\r]

자바의 Character 클래스와 같은 방식으로 사용하려면 다음과 같이 사용 가능하다.

\p{javaLowerCase} Equivalent to java.lang.Character.isLowerCase()
\p{javaUpperCase} Equivalent to java.lang.Character.isUpperCase()
\p{javaWhitespace} Equivalent to java.lang.Character.isWhitespace()
\p{javaMirrored} Equivalent to java.lang.Character.isMirrored()

유니코드를 처리하기 위해서는 다음과 같이 사용하면 된다. (한글에 대해서는 아직 테스트 해보지 않았다. ^^)

\p{InGreek} A character in the Greek block (simple block)
\p{Lu} An uppercase letter (simple category)
\p{Sc} A currency symbol
\P{InGreek} Any character except one in the Greek block (negation)
[\p{L}&&[^\p{Lu}]]  Any letter except an uppercase letter (subtraction)

각 경계값을 나타내는 것은 다음과 같이 할 수 있다.

^ The beginning of a line
$ The end of a line
\b A word boundary
\B A non-word boundary
\A The beginning of the input
\G The end of the previous match
\Z The end of the input but for the final terminator, if any
\z The end of the input

이제부터 정신을 바짝 차려야 하는데, 위의 각 방법을 조합해서 각 문자의 횟수를 다음과 같이 지정할 수 있다.
(이를 Greedy quantifiers라고 부른다.)

X? X, once or not at all
X* X, zero or more times
X+ X, one or more times
X{n} X, exactly n times
X{n,} X, at least n times
X{n,m} X, at least n but not more than m times

그리고, ? 와 +를 사용하여 각각 제외 및 포함의 의미를 나타낸다. 각 예는 다음과 같다.

Reluctant quantifiers
X?? X, once or not at all
X*? X, zero or more times
X+? X, one or more times
X{n}? X, exactly n times
X{n,}? X, at least n times
X{n,m}? X, at least n but not more than m times

Possessive quantifiers
X?+ X, once or not at all
X*+ X, zero or more times
X++ X, one or more times
X{n}+ X, exactly n times
X{n,}+ X, at least n times
X{n,m}+ X, at least n but not more than m times

논리 부분은 다음과 같이 표시한다.

XY X followed by Y
X|Y Either X or Y
(X) X, as a capturing group

특수 Construct는 다음과 같다.

(?:X) X, as a non-capturing group
(?idmsux-idmsux)  Nothing, but turns match flags i d m s u x on - off
(?idmsux-idmsux:X)   X, as a non-capturing group with the given flags i d m s u x on - off
(?=X) X, via zero-width positive lookahead
(?!X) X, via zero-width negative lookahead
(?<=X) X, via zero-width positive lookbehind
(?<!X) X, via zero-width negative lookbehind
(?>X) X, as an independent, non-capturing group

기타 관련 Construct들은 다음과 같다.

Back references
\n Whatever the nth capturing group matched

Quotation
\ Nothing, but quotes the following character
\Q Nothing, but quotes all characters until \E
\E Nothing, but ends quoting started by \Q

이 내용들에 대해서는 한번 쭉~~~ 읽어보면 이해가 되겠지만, 예제를 봐야지만 보다 더 쉽게 이해할 수 있으리라 생각된다.

다음 글에는 예제를 통해서 각 Regular Expression을 어떻게 사용하는지 정리하도록 하겠다.

Posted by tuning-java

String 데이터를 처리하기 위한 코딩을 할 때 알아두면 굉장히 도움 되는 것이 Regular Expression이다.

이게 뭔지도 모르신다면, 아래의 링크를 따라가서 한번 읽어 보시기를 권장한다.

http://java.sun.com/docs/books/tutorial/essential/regex/index.html

예를 들어 e-mail 주소나 URL의 정합성을 체크할 때 굉장히 편하게 사용할 수 있다.
Regular Expression을 주로 사용하는 언어들은 grep, Perl, Tcl, Python, PHP, awk 등이 있다.

Java 에서도 JDK 1.4 버젼부터 Regular Expression을 사용하기 시작했으며, java.util.regex.Pattern 클래스의 API 를 보면 Regular Expression에서 사용되는 패턴 구성을 볼 수 있다.

참고로,이미 만들어진 Regular Expression 들을 참조하고 싶다면, 아래의 사이트를 방문하기 바란다.
http://regexlib.com/

그럼 간단하게 Java를 이용해서 Regular Expression을 사용하는 방법에 대해서 알아보자.

import java.util.Scanner;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class RegexTester {

    public static void main(String[] args){
        RegexTester rt=new RegexTester();
        while(true) {
            rt.checkRegularExpression();
        }
    }
    public void checkRegularExpression() {       
        Scanner sc=new Scanner(System.in);
        System.out.print("Enter Regular expression pattern : ");
        String regex=sc.nextLine();
        while(check(regex));
    }
    public boolean check(String regex) {
        Scanner sc=new Scanner(System.in);
        System.out.print("Enter data: ");
        String data=sc.nextLine();
            Pattern samplePattern = Pattern.compile(regex);
            Matcher matcher = samplePattern.matcher(data);
            boolean found = false;
            while (matcher.find()) {
                System.out.format("Text \"%s\" is found : from index %d - to index %d.\n",
                    matcher.group(), matcher.start(), matcher.end());
                found = true;
            }
            if(!found){
                System.out.format("No match found.\n");
            }
            System.out.print("Check another data ? [Y or y] or Quit [Q or q] : ");
            String another=sc.nextLine();
            if(another.equals("Q") || another.equals("q")) {
                System.exit(0);
                return false;
            } else if(another.equals("Y") || another.equals("y")) {
                return true;
            } else {
                return false;
            }
    }

}

이 프로그램은 Regular Expression을 입력하고, 문자열을 입력하면 입력된 문자열중 Regular Expression과 맞는 (match되는) 문자열이 어떤것이 있는지를 화면에 뿌려준다.

실행 결과 예는 다음과 같다.

Enter Regular expression pattern : [abc]
Enter data: abcdefg
Text "a" is found : from index 0 - to index 1.
Text "b" is found : from index 1 - to index 2.
Text "c" is found : from index 2 - to index 3.
Check another data ? [Y or y] or Quit [Q or q] : y
Enter data:
No match found.
Check another data ? [Y or y] or Quit [Q or q] : y
Enter data: cbfhgft
Text "c" is found : from index 0 - to index 1.
Text "b" is found : from index 1 - to index 2.
Check another data ? [Y or y] or Quit [Q or q] : q

다음 글에는 Regular Expression을 어떻게 지정하는지 알아보자.

Posted by tuning-java