6 minute read

봐도봐도 또 기억안나는 정규표현식 이번엔 완벽히,, 정리해보자

0. 목차

  1. 정규 표현식이란?
  2. 정규표현식 정
  3. 정규식을 지원하는 String 메서드
  4. java.util.regex.Pattern
  5. java.util.regex.Matcher
  6. 재미있는 예제 anagram

1. 정규 표현식(Regular Expression)이란?

정규 표현식이란 컴퓨터 과학의 정규언어로 부터 유래한 것으로 특정한 규칙을 가진 문자열의 집합을 표현하기 위해 쓰이는 형식 언어이다.

2-1. 정규표현식 정리

정규 표현식에서 사용되는 기호를 Meta문자라 하고, 표현식에서 내부적으로 특정 의미를 가지는 문자를 말한다.

  • ^ : 문자열의 시작
    • ex) ^x : 문자열의 시작을 표현하며 x문자로 시작됨
  • $ : 문자열의 종료
    • ex) x$ : 문자열의 종료를 표현하며 x문자로 종료됨
  • . : 임의의 한 문자 (문자의 종류 가리지 않음)
    • ex) .x : 임의의 한 문자의 자리수를 표현하며 문자열이 x로 끝남을 의미
  • * : 앞 문자가 없을 수도 무한정 많을 수도 있다.
    • ex) x* : 반복여부를 표현하며 x문자가 0번 또는 그 이상 반복됨을 의미,
  • + : 앞 문자가 하나 이상 존재 해야 한다.
    • ex) x+ : 반복을 표현하며, x문자가 한번 이상 반복됨을 의미
  • ? : 앞 문자가 없거나 하나 있다.
    • ex) x? : 존재여부를 표현하며 x문자가 존재할수도 있고 없을 수 도 있다.
  • [] : 문자의 집합이나 범위를 나타내며 두문자 사이는 - 기호로 범위를 나타낸다. []내에서 ^가 선행하여 존재하면 not을 나타낸다.
    • ex1) [xy] : 문자 선택을 표혀하며 x와 y중에 하나를 의미
    • ex2) [^xy] : not을 표현하며 x 및 y를 제외한 문자를 의미
    • ex3) [x-y] : range를 표현하며 x~z 사이의 문자를 의미
  • {} : 횟수 또는 범위를 나타낸다.
    • ex1) x{n} : 반복을 표현하며 x문자가 n번 반복됨을 의미
    • ex2) x{n,} : 반복을 표현하며 x문자가 n번 이상 반복됨을 의미
    • ex3) x{n,m} : 반복을 표현하며 x문자가 최소 n번이상 최대 m번 이하로 반복됨을 의
  • () : 소괄호 안의 문자를 하나의 문자로 인식한다.
    • ex1) (x) : 그룹을 표현하며 x 를 그룹으로 처라함을 의미
    • ex2) (x)(y) : 그룹들의 집합을 표현하며 앞에서 부터 순서대로 번호를 부여 하여 관리, x, y는 각 그룹의 데이터로 관리
    • ex3) (x)(?:y) : 그룹들의 집합에 대한 예외를 표현하며 그룹 집합으로 관리되지 않음을 의미
  • : 패턴 안에서 or 연산을 수행할 때 사용
    • x y : or를 표현하며 x 또는 y문자가 존재함을 의미
  • \s : 공백 문자
  • \S : 공백 문자가 아닌 나머지 문자
  • \w : 알파벳이나 숫자
  • \W : 알파벳이나 숫자를 제외한 문자
  • \d : 숫자 0~9
  • \D : 숫자를 제외한 모든 문자
  • \ : 정규 표현식 역슬래시 ())는 확장 문자, 역슬래시 다음에 일반 문자가 오면 특수 문자로 취급하고, 역슬래시 다음에 특수문자가 오면 그 문자 자체를 의미한다.
  • (?i) : 앞 부분에 (?i) 라는 옵션이 있으면 대소문자를 구분하지 않는다.

2-2. 정규식 사용 방법

^[0-9]*$ 를 뜯어 보자
  1. ^ 으로 우선 패턴의 시작을 알린다.
  2. [0-9] 괄호사이에 두 숫자를 넣어 범위를 지정
    • 를 넣어 글자의 수를 상관하지 않고 검사한다.
  3. $ 으로 패턴의 종료를 알림

즉 위의 예제는 0~9 까지의 숫자를 글자 수를 제한하지 않고 검사하는 패턴이다.

2-3. 문자 정규식

  • [abc] : a 또는 b 또는 c 중 하나
  • [^abc] : a, b, c가 아닌 문자 중 하나
  • [a-zA-z] : 알파벳 중 하나
  • [a-d[m-p]] : a에서 d혹은 m에서 p 까지 중 하나
  • [a-z&&[def]] : d 또는 e 또는 f 중 하나
  • [a-z&&[^bc]] : a에서 z 중 b 와 c를 제외한 문자 하나
  • [a-z&&[^m-p]] : a에서 z 중 m 에서 p를 제외한 문자 하

2-4. 자주 사용하는 정규 표현식

숫자만 가능 : [ 0 ~ 9 ] 주의 : 띄어쓰기 불가능

  • /^[0-9]+$/

이메일 형식만 가능

  • /^([\w-]+(?:.[\w-]+))@((?:[\w-]+.)\w[\w-]{0,66}).([a-z]{2,6}(?:.[a-z]{2})?)$/

한글만 가능 : [ 가나다라 … ] 주의 : ㄱㄴㄷ… 형식으로는 입력 불가능 , 띄어쓰기 불가능

  • /^[가-힣]+$/

한글,띄어쓰기만 가능 : [ 가나다라 … ] 주의 : ㄱㄴㄷ… 형식으로는 입력 불가능 , 띄어쓰기 가능

  • /^[가-힣\s]+$/

영문만 가능 :

  • /^[a-zA-Z]+$/

영문,띄어쓰기만 가능

  • /^[a-zA-Z\s]+$/

전화번호 형태 : 전화번호 형태 000-0000-0000 만 받는다. ]

  • /^[0-9]{2,3}-[0-9]{3,4}-[0-9]{4}$/

도메인 형태, http:// https:// 포함안해도 되고 해도 되고

  • /^(((http(s?)):\/\/)?)([0-9a-zA-Z-]+.)+[a-zA-Z]{2,6}(:[0-9]+)?(\/\S*)?$/

도메인 형태, http:// https:// 꼭 포함

  • /^((http(s?)):\/\/)([0-9a-zA-Z-]+.)+[a-zA-Z]{2,6}(:[0-9]+)?(\/\S*)?$/

도메인 형태, http:// https:// 포함하면 안됨

  • /^[^((http(s?)):\/\/)]([0-9a-zA-Z-]+.)+[a-zA-Z]{2,6}(:[0-9]+)?(\/\S*)?$/

한글과 영문만 가능

  • /^[가-힣a-zA-Z]+$/;

숫자,알파벳만 가능

  • /^[a-zA-Z0-9]+$/;

주민번호, -까지 포함된 문자열로 검색

  • /^(?:[0-9]{2}(?:0[1-9] 1[0-2])(?:0[1-9] [1,2][0-9] 3[0,1]))-[1-4][0-9]{6}$/

3. 정규식을 지원하는 String 메서드

String 클래스에는 Regex를 지원하는 메소드들이 있다.

  • String.matches(regex) : String이 regex와 일치하면 true 리턴
  • String.split(regex) : regex와 일치하는 것을 기준으로 String을 분리하여 배열로 리턴
  • String.replaceFirst(regex, replacement) : regex와 가장 먼저 일치하는 것을 replacement로환 변환
  • String.replaceAll(regex, replacement) : regex와 일치하는 모든 것을 replacement로 변
public class example {
    public static void main(String[] args) {

        // 1. .은 문자 한개에 해당한다.
        String pattern = "ab.";
        System.out.println("abc".matches(pattern));
        System.out.println("ab ".matches(pattern)); // whitespace 도 문자로 카운트
        System.out.println("ab".matches(pattern));

        System.out.println("");

        // 2. \s 는 whitespace 한개, \S 는 whitespace를 제외한 문자 한개를 의미
        pattern = "ab\\s\\S";
        System.out.println("ab  ".matches(pattern));
        System.out.println("ab c".matches(pattern));

        // 3. ^는 문자열의 시작지점을 찾는다. 따라서 ^ 다음으로 오는 패턴으로 문자열이 시작되는 것을 찾는다.
        // 아래 regex와 일치하는 내용을 replacement로 교체 한다. 결과에서 * 로 변경된 내용이 regex와 일치하는 것이라고 생각한다.

        String result = "The cat sat on the mat.".replaceAll("[Tt]he", "*");
        System.out.println(result);

        result = "The cat sat on the mat.".replaceAll("^[Tt]he", "*");
        System.out.println(result);

        // 4. $는 문자열의 종료 지점을 찾는다. 따라서 $ 앞 패턴으로 문자열이 끝나는 것을 찾는다.
        result = "The cat sat on the mat. and the cat".replaceAll("cat", "*");
        System.out.println(result);

        result = "The cat sat on the mat. and the cat".replaceAll("cat$", "*");
        System.out.println(result);

        // 5. \b 는 단어의 경계선을 찾는 역할을 한다. 단여 양옆에 \b를 사용하여 다른 문자와 결합되지 않은, 독립적인 단어를 찾을 수 있다.
        result = "This island is beautiful.".replaceAll("is", "*");
        System.out.println(result);

        result = "This island is beautiful".replaceAll("\\bis\\b", "*");
        System.out.println(result);

        // 6. []는 내부의 문자열과 일치하는 문자 1개를 찾는다. -를 사용하면 범위 또한 지정이 가능하다.
        pattern = "[abc][vz]";
        System.out.println("av".matches(pattern));
        System.out.println("cz".matches(pattern));
        System.out.println("ac".matches(pattern));

        pattern = "Ex_[a-g1-5]";
        System.out.println("Ex_g".matches(pattern));
        System.out.println("Ex_6".matches(pattern));

        // 숫자, 문자, 공백을 표현하는 Metacharacters들에 대한 예제. 자바는 \를 표현하기 위해선 \\로 입력을 해야 한다.
        pattern = "\\d\\D";
        System.out.println("1a".matches(pattern));
        System.out.println("a1".matches(pattern));
        System.out.println("11".matches(pattern));

        pattern = "\\d\\s\\D";
        System.out.println("1 a".matches(pattern));

        pattern = "\\d\\s\\d\\D";
        System.out.println("1 1a".matches(pattern));

        pattern = "\\d\\s\\S\\D";
        System.out.println("1 1a".matches(pattern));

        pattern = "\\w\\W";
        System.out.println("1 ".matches(pattern));

        // Quantifiers
        // *, +, ?, {}, *?
        // * 은 * 앞의 요소가 0번 이상 반복되는 것을 의미

        pattern = "a*[0-9]*";
        System.out.println("aaa123".matches(pattern));
        System.out.println("aaa".matches(pattern));

        // + 은 + 앞의 요소가 1번 이상 반복되는 것을 의미
        pattern = "a+[0-9]+";
        System.out.println("aaa123".matches(pattern));
        System.out.println("aaa".matches(pattern));

        // ? 은 요소가 0 또는 1회만 반복되는 것을 의미
        pattern = "a*[0-9]?";
        System.out.println("aaa".matches(pattern));
        System.out.println("aaa12".matches(pattern));

        // {x,y} 는 x,y 사이의 수만큼 반복된 다는것을 의미, 위에서 문자열 1개로 처리했던 것을 모두 표현 가능
        pattern = "a*[0-9]{2,3}";
        System.out.println("aaa".matches(pattern));
        System.out.println("aaa12".matches(pattern));

        pattern = "a{2,3}[0-9]{2,3}";
        System.out.println("aaa12".matches(pattern));
    }
}

4. java.util.regex.Pattern

Pattern 객체 정규 표현식에 대상 문자열을 검증하는 기능으로 java.util.regex.Pattern 이 사용된다.

정규식의 컴파일된 표현 (정규식을 적용 가능하도록 컴파일 하여 가지고 있다.) Pattern 클래스는 공개된 생성자를 제공하지 않는다. 패턴을 생성하려면 Pattern 객체를 반환하는 정적 compile 메소드를 호출해야 한다. 이 메소드는 첫 번째 인자로 정규식 문자열을 받아 들인다.

String.matche 와 Pattern.matches

public class PatternEx {

  public static void main(String[] args) {
    String pattern = "^[0-9]*$";
    String val = "123456789";

    boolean regex = Pattern.matches(pattern, val);
    System.out.println(regex); // true

    System.out.println(val.matches(pattern)); // true
  }
}

두개의 결과가 같다. 그럼 왜 Pattern 클래스를 사용하는가?? Pattern 클래스는 아래와 같은 기능들을 더 가지고 있다.

Pattern 주요메서드 compile(String regex) : 주어진 정규 표현식으로 부터 패턴을 만든다. matcher(CharSequence input) : 대상 문자열이 패턴과 일치할 경우 true를 반환한다. asPredicate() : 문자열을 일치시키는 데 사용할 수 있는 사술어를 작성한다. pattern() : 컴파일된 정규표현식을 String 형태로 반환한다. split(CharSequence input) : 문자열을 주어진 인자값 CharSequence 패턴에 따라 분리한다.

Pattern 플래그 (상수)값 사용 Pattern.CANON_EQ : None표준화된 매칭 모드를 활성화 Pattern.CASE_INSENSITIVE : 대소문자를 구분하지 않는다. Pattern.COMMENT : 공백과 #으로 시작하는 주석이 무시된다. Pattern.MULTILINE : 수식 ^는 라인 시작, $는 라인의 끝과 매치된다. Pattern.DOTALL : 수식 .과 모든 문자와 match 되고 \n도 match 에 포함된다. Pattern.UNICODE_CAE : 유니코드를 기준으로 대소문자 구분없이 match 시킨다. Pattern.UNIX_LINES : 수식 .과 ^및 $의 match시에 한라인의 끝을 의미하는 \n만 인식된다.

5. java.util.regex.Matcher

6. 예제 anagram

public class Anagram {

    public static boolean isAnagram(String s1, String s2) {

        // 공백 제거
        s1 = s1.replaceAll("\\p{Z}","");
        s2 = s2.replaceAll("\\p{Z}","");

        if (s1.length() != s2.length()) {
            return false;
        }

        // 소문자로 변환 + char 배열 변환
        char[] c1 = s1.toLowerCase().toCharArray();
        char[] c2 = s2.toLowerCase().toCharArray();

        // Arrays.sort() 오름 차순 정렬
        Arrays.sort(c1);
        Arrays.sort(c2);

        String sc1 = new String(c1);
        String sc2 = new String(c2);

        if (sc1.equals(sc2)) {
            return true;
        } else {
            return false;
        }
    }

    public static void main(String[] args) {
       if(isAnagram("Justin Timberlake", "Im a jerk but listen")) {
           System.out.println("These sequence are anagram");
       } else {
           System.out.println("These sequence are not anagram");
       }
    }
}

위 코드를 좀 더 똑똑하게 꾸며볼 수 있겠지만 ,, 여기선 그렇게 까지 만들지는…

Java 정규 표현식(Regular Expression)의 이해 - 엄청 잘되어 있는

Categories:

Updated: