자바 정규식 기본정리 : Matcher, Pattern, find(), group()

자바 정규식 기본정리 : Matcher, Pattern, find(), group()

정규식을 사용하면 문자열(String)이 특정 패턴과 일치하는지 여부를 확인하거나, 패턴에 맞는 값을 찾아내거나, 해당 값을 새로운 값으로 바꿀 수 있다.

이 방법이 일목요연하게 작성되어 있는 곳이 마땅히 보이지 않았기에 직접 정리해서 써본다.

1. matches (일치하는지 확인)

target 은 대상이 되는 문자열(문장)을 담는 변수이고, regEx는 정규식(Regular Expression) 을 담는 변수라고 해보자.

public void isEqualRegEx() {
    String target = “나는 2008년도에 입학했다.”;
    String regEx = “.*\\d{1}.*”;
    // String regEx = “.*[0-9].*”; 와 동일함
  
    if (target.matches(regEx)) {
        System.out.println(“일치”);
   
    } else {
        System.out.println(“불일치”);
    }
}

여기서 regEx 는 “.*\\d{1}.*”; 이다. 즉 여기서 target.matches(regEx) 는 숫자가 1개라도 포함되어 있느냐고 묻는 것이다.
(“.*” 는 모든 복수의 문자이고, “\\d{1}”는 한 자리 숫자이므로.)

이 경우 2008, 이렇게 숫자가 4개나 있으니까 당연히 “일치”가 출력되겠지.
만약 regEx 값이 바뀐다면 어떨까?

regEx == “.*\\d{1}.*”  -> 일치
regEx == “.*[0-9].*”  -> 일치 ([0-9]는 \\d{1} 와 정확히 같은 뜻임)

regEx == “.*[0-9][0-9][0-9][0-9].*” -> 일치 (숫자 4자리)
regEx == “.*[0-9][0-9][0-9][0-9][0-9].*” -> 불일치 (숫자 5자리)

regEx == “.*\\d{1,4}.*” -> 일치 (숫자 1자리 이상 4자리 이하)
regEx == “.*\\d{2,5}.*” -> 일치 (숫자 2자리 이상 5자리 이하)
regEx == “.*\\d{5,6}.*” -> 불일치 (숫자 5자리 이상 6자리 이하)

요런 식으로 되겠다.

2. replaceAll (패턴에 맞는 값을 새로운 값으로 치환)

public void replaceRegEx() {
    String target = “나는 2008년도에 입학했다.”;
    String regEx = “[0-9]”;
    Pattern pat = Pattern.compile(regEx);
  
    Matcher m = pat.matcher(target);
    String result = m.replaceAll(“2”); // 패턴과 일치할 경우 “2”로 변경
    
    System.out.println(“출력 : ” + result);
    // 출력 : 나는 2222년도에 입학했다.
}

여기서 regEx 변수 값은 “[0-9]” 이다. 그러니까 위 소스는 1자리 숫자들을 “2”로 치환하게 된다.
결과는 당연히 “나는 2222년도에 입학했다.”가 된다.

위 함수를 3줄로 줄이면 아래와 같다.

public void replaceRegEx() {
    String target = “나는 2008년도에 입학했다.”;
    String regEx = “[0-9]”;
    System.out.println(“출력 : ” + target.replaceAll(regEx, “2”));
}

String 객체에 replaceAll 라는 멤버함수가 있다. 이게 더 낫다.
전자는 Pattern 객체와 Matcher 객체를 추가로 임포트하는데, 후자는 String 객체만 있으면 되니까.

3-1. find(), group() (패턴에 맞는 값 1개씩 찾아내기)

요 find랑 group이라는 함수가 특이한데 Matcher 의 멤버함수다.
일단 단순무식한 코드로 배워보자.

public void findRegEx(){
    String target = “나는 2008년도에 입학했다.”;
    String regEx = “[0-9]”;


    // 정규식(regEx)을 패턴으로 만들고,
    Pattern pat = Pattern.compile(regEx);
    // 패턴을 타겟 스트링(target)과 매치시킨다.
    Matcher match = pat.matcher(target);


    System.out.println(match.find());  // true
    System.out.println(match.group()); // 2
    
    System.out.println(match.find());  // true
    System.out.println(match.group()); // 0
    
    System.out.println(match.find());  // true
    System.out.println(match.group()); // 0
    
    System.out.println(match.find());  // true
    System.out.println(match.group()); // 8
    
    System.out.println(match.find());  // false
    System.out.println(match.group()); // 에러 발생! (IllegalStateException)
}

Pattern에 compile로 정규식(regEx)을 담고, Matcher에 타겟 스트링(target)을 담는게 먼저다.

그 다음 Matcher의 find() 함수를 쓰면 1번째 값을 찾아내고, true 혹은 false를 반환한다.
group() 을 쓰면 방금 찾은 1번째 스트링이 튀어나온다.

다시 find()를 쓰면 2번째 값을 찾고, group()을 쓰면 2번째 값이 튀어나오고… 이런 식이다.

보면 2, 0, 0, 8 까지 잘 가다가 (숫자가 더 이상 없으므로 당연히) 5번째에서 에러가 나는데,
따라서 에러가 나지 않도록 코드를 쓴다면 아래와 같이 작성해야 마땅하겠다.

…(전략)…

    if (match.find()) {
        System.out.println(match.group());
    }

…(후략)…

3-2. find(), group() (패턴에 맞는 값 모두 찾아내기)
3-1에서 설명한 바를 잘 정리한게 아래 메서드다.

public void findAllRegEx(){
    String target = “나는 2008년도에 입학했다.”;
    String regEx = “[0-9]”;

    Pattern pat = Pattern.compile(regEx); 
    Matcher match = pat.matcher(target);
    
    int matchCount = 0;
    while (match.find()) {
        System.out.println(matchCount + ” : ” + match.group());
        matchCount++;
    }
    System.out.println(“총 개수 : ” + matchCount);
    
    // 0 : 2
    // 1 : 0
    // 2 : 0
    // 3 : 8
    // 총 개수 : 4
}

보시다시피 while문을 사용해 find()가 false가 될 때까지 루프를 돌리면 된다.

끝. bb_ 2016-11-16 18:03