기타/프로그래밍

정규표현식

ysk(0soo) 2022. 8. 31. 14:35

정규표현식(Regular Expression)

  • 정규표현식(Regular Expression) 줄여서 Regex 라고 표현
  • 특정한 규칙을 가진 무자열의 집합을 표혀낳는 사용하는 형식 언어
  • 문자열에서 특정 패턴을찾거나 존재하는지, 또는 검증할 때 사용
  • 정규 표현식의 각 문자(즉, 패턴을 기술하는 문자열 안의 각 문자)는 메타문자(특별한 의미로)로 이해되거나 정규 문자('문자 그대로', 즉 '리터럴'의 의미로)로 이해된다
    • 정규식 a. a는 단지 'a'와 일치하는 리터럴 문자이며 .는 새 줄을 제외한 모든 문자와 일치시키는 메타 문자이다

Java에서의 정규표현식

  • java.util.regex 패키지에 있는 클래스들을 사용한다.

  • Pattern클래스 - 패턴 정의(검색에 사용됨)
  • Matcher클래스 - 패턴 검색에 사용
  • PatternSyntaxException클래스 - 정규식 패턴의 구문 오류를 나타냅니다.

정규 표현식의 Pattern클래스의 matchers()메서드를 사용하여 해당문자열이 패턴과 일치하는지 확인합니다 matches(String regex, CharSequence input)을 사용합니다

  • public static boolean matches(String regex, CharSequence input)
    • 패턴에 일치하면 true 틀리면 false를 반환
@Test
void regexTest() {
      String pattern = "^[a-zA-Z]*$"; //영어만
      String str = "abcde";
      boolean matches = Pattern.matches(pattern, str);
      System.out.println(matches); // 패턴에 맞으므로 true 반환 
}

Pattern 클래스 주요 메서드

  • compile(String regex) : 정규표현식의 패턴을 작성
  • matches(String regex, CharSequence input)
    • 정규표현식의 패턴과 문자열이 일치하는지 체크
    • 일치할 경우 true, 일치하지 않는 경우 false를 리턴

Matcher 클래스 주요 메서드

  • matches()
    • 정규표현식의 패턴과 문자열이 일치하는지 체크
    • 일치할 경우 true, 일치하지 않는 경우 false를 리턴
  • find()
    • 정규표현식의 패턴과 문자열이 일치하는지 체크합니다 그리고 그 위치로 이동
    • 일치할 경우 true, 일치하지 않는 경우 false를 리턴
  • find(int start)
    • start위치부터 find() 작업을 수행
  • group()
    • 매칭된 부분 중 첫 번째 그룹을 리턴합니다
  • group(int group)
    • 매칭된 부분중 group번째 그룹을 리턴합니다
    • 범위를 벗어나면 IndexOutOfBondsException 발생
  • groupCount()
    • 매칭된 group의 전체 갯수를 리턴합니다

  • 다음과 같이 사용할 수도 있다.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
​
public class Main {
  public static void main(String[] args) {
    Pattern pattern = Pattern.compile("pattern", Pattern.CASE_INSENSITIVE);
    Matcher matcher = pattern.matcher("패턴");
   
    boolean matchFound = matcher.find();
    
    if(matchFound) {
      System.out.println("Match found");
    } else {
      System.out.println("Match not found");
    }
  }
}
  • Pattern.compile()먼저 메서드 를 사용하여 패턴을 만듭니다.
    • 첫 번째 매개변수는 검색 중인 패턴을 나타내고 두 번째 매개변수에는 검색이 대소문자를 구분하지 않아야 함을 나타내는 플래그가 있습니다.
    • 두 번째 매개변수는 선택 사항입니다.
  • matcher()메서드는 문자열에서 패턴을 검색하는 데 사용됩니다. 수행된 검색에 대한 정보가 포함된 Matcher 개체를 반환합니다.
  • find()메서드는 문자열에서 패턴을 찾으면 true를 반환하고 찾지 못하면 false를 반환합니다.

메서드 의 Flag compile()는 검색이 수행되는 방식을 변경한다.

  • Pattern.CASE_INSENSITIVE- 검색시 대소문자는 무시됩니다.
  • Pattern.LITERAL- 패턴의 특수문자는 특별한 의미가 없으며 검색시 일반문자로 처리됩니다.
  • Pattern.UNICODE_CASE- 플래그와 함께 사용하여 CASE_INSENSITIVE영문자 이외의 문자도 무시

java에서의 정규표현식의 활용

  1. 문자열에서 알파벳 대문자, 숫자, 더하기(+), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거하라
  2. 문자열에서 마침표(.)가 3번 이상 연속된 부분을 하나의 마침표(.)로 치환하라
private String removeChar(String input) {
  return input.replaceAll("[^A-Z0-9+_.]", ""); // 1번. 제거
}
​
private String changeDot(String input) {
  return input.replaceAll("[.]{3,}", "."); // 2번 .로 replace
}

String Class의 replaceAll() 메서드

public String replaceAll(String regex, String replacement) {
  return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
  • Pattern.compile()을 사용하고 있다.
/// Pattern.compile() 메서드
​
    /**
     * Compiles the given regular expression into a pattern.
     *
     * @param  regex
     *         The expression to be compiled
     * @return the given regular expression compiled into a pattern
     * @throws  PatternSyntaxException
     *          If the expression's syntax is invalid
     */
public static Pattern compile(String regex) {
  return new Pattern(regex, 0);
}
  • 항상 패턴으로 새로운 패턴을 만든다. (new)
  • 사실상 패턴을 바뀔일이 없으므로 pattern을 정적 상수로 선언하여 재활용성을 높이자
private static final Pattern REMOVE_CHAR_PATTERN = Pattern.compile("[^A-Z0-9+_.]");
private static final Pattern CHANGE_DOT_PATTERN = pattern.compile("[.]{3,}");
​
private String removeChar(String input) {
  return REMOVE_CHAR_PATTERN.matcher(input).replaceAll("");
}
​
private String changeDot(String input) {
  return CHANGE_DOT_PATTERN.matcher(input).repliaceAll(".");
}

Pattern 클래스는 정적 팩토리 메서드를 사용하고 있으며 Thread-safe 하다

Pattern 객체는 불변 객체이다.

Matcher 클래스 사용시 주의할점

Matcher 객체는 reset() 하고 다시 input 값을 넣어서 재사용해줄 수 있지만 Thread-safe 하지못하다.

  • Matcher Class의 reset() 메서드
public Matcher reset() {
  ....
  return this;
}

그러므로 Thread-safe 하게 사용하려면 Pattern 객체의 matcher()를 통해 Matcher를 새로 생성한 뒤 사용하자


정규표현식 문법

Regular ExpressionsDescriptionExample

. 임의의 문자 1개를 의미  
^ 시작을 의미한다. [ ] 괄호 안에 있다면 일치하지 않는 부정의 의미로로 쓰인다 ^a : a로 시작하는 단어 a : a가 아닌 철자인 문자 1개 예를 들면 abcd는 ad, bd, cd는 포함하지 않고 ed, fd 등을 포함한다. a-z는 알파벳 소문자로 시작하지 않는 모든 문자를 의미
$ $앞의 문자열로 문자가 끝나는지를 의미한다. 문자열의 끝 a$ : a로 끝나는 단어
[] [] 괄호 안의 문자가 있는지를 확인한다 ab : a,b중 한 문자와 c,d중 한 문자 -> ac ad bc bd [xy] 문자 선택을 표현하며 x 와 y 중에 하나를 의미한다. xy not 을 표현하며 x 및 y 를 제외한 문자를 의미한다. [x-z] range를 표현하며 x ~ z 사이의 문자를 의미한다.
- 사이의 문자 혹은 숫자를 의미한다 출처: https://hamait.tistory.com/342 HAMA 블로그:티스토리 : 알파벳 소문자 a부터 z까지. [a-z0-9] : 알파벳 소문자 전체,0~9 중 한 문자 예를 들면 [abc]d는 ad, bd, cd를 뜻한다. 또한, "-" 기호와 함께 쓰면 범위를 지정할 수 있다. "[a-z]"는 a부터 z까지 중 하나, "[1-9]"는 1부터 9까지 중의 하나를 의미한다.
| or 조건 (또는). 왼쪽 호는 오른쪽과 일치 [a|b] : a 혹은 b
() 그룹 01 (0|1) : 01뒤에 0 또는 1이 들어간다 -> 010(o), 011(o), 012(x)
{} 개수 a{3}b : a가 3번 온 후 b가 온다 -> aab(x), aaab(o), aaaab(o)
\b 공백, 탭, ",", "/" 등을 의미한다 apple\b : apple뒤에 공백 탭등이 있다 -> apple juice (o), apple.com (x)
\B \b의 부정 공백 탭등이 아닌 문자인 경우 매치한다 apple\b -> apple.com (o)
\d 0~9 사이의 숫자 [0-9]와 동일  
\D \d의 부정 숫자가 아닌 어떤 문자, 0-9와 동일  
\s 공백, 탭  
\S 공백, 탭이 아닌 문자  
\w 알파벳 대소문자+숫자+"_" [a-zA-Z_0-9]와 동일  
\W \w의 부정 a-zA-Z_0-9  
\A 문자열의 시작점을 일치시킨다.  
\z 문자열의 끝  
\s 공백 문자  
\S 공백문자가 아닌 나머지와 일치  

위치 문자설명

^a 단어의 맨 앞에 위치한 해당 패턴만을 검색함. (ex : 'a'로 시작하는 단어의 'a'만을 검색함.)
a$ 단어의 맨 뒤에 위치한 해당 패턴만을 검색함. (ex : 'a'로 끝나는 단어의 'a'만을 검색함.)

수량 표현식

Regular ExpressionsDescriptionExample

? 앞의 표현식이 0개 이상이다 a1? : 1이 있을수도 없을수도 있다 -> a (o), a1(o), a2(o)
* 앞의 표현식이 0개 이상이다. 문자가 없는 경우나 하나 이상 연속하는 문자 찾기. a1* : 1이 있을수도 없을수도 있다 -> a (o), a1(o), a2(o)
+ 1개 이상 찾기. a1* : 1이 1개 이상있다 -> a (x), a1(o), a11(o)
{n} n개 있다 (n번 반복) a{3} : a가 3개 있다 -> aa(x), aaa(o), aaaa(o)
{n, m} n개 이상 m개 이하 a{3,5} : a가 3개 or 4개 or5개 있다 -> aa(x), aaa(o), aaaa(o), aaaaaaa(o)
{n,} n개 이상(m제거), (n번 이상 반복) a{3,} : a가 3개 이상 있다 -> aa(x), aaa(o)

괄호설명

a(b)c 전체 패턴을 검색한 후에 괄호 안에 명시된 문자열을 저장함. (ex : "abc"를 검색한 후에 b를 저장함.)
[abc] 꺾쇠 괄호([]) 안에 명시된 문자를 검색함. (ex : "abc"를 검색함.)
[0-3] 꺾쇠 괄호([]) 안에 명시된 숫자를 검색함. (ex : 0부터 3까지의 숫자를 검색함.)
[\b] 백스페이스 문자를 검색함.
{n} 앞의 문자가 정확히 n번 나타나는 경우를 검색함. n은 반드시 양의 정수이어야만 함.
{m,n} 앞의 문자가 최소 m번 이상 최대 n번 이하로 나타나는 경우를 검색함. m과 n은 반드시 양의 정수이어야만 함.
  • Escape: 정규표현식 패턴이 아닌 문자로 사용하고 싶을때는 앞에 \(역슬래시)를 앞에 붙이기

Flag

정규표현식을 사용할 때 Flag 라는 것이 존재하는데 Flag를 사용하지 않으면 문자열에 대해서 검색을 한번만 처리하고 종료하게 된다.

Flag는 다음과 같은 것들이 존재한다.

Flag의미

g Global 을 표현하며, 대상 문자열 내에 모든 패턴들을 검색하는것을 의미.
i Ignore case 을 표현하며 대상 문자열에 대해서 대/소문자를 구별하지 않는것
m Multi line을 표현하며 대상 문자열이 다중 라인의 문자열인 경우에도 검색하는 것을 의미한다. 행이 바뀌어도 찾는다.

전방 탐색

이외의 방식

자주 사용하는 정규표현식 예제

  • ^[0-9]*$ : 숫자
  • ^[a-zA-Z]*$ : 영문자
  • ^[가-힣]*$ : 한글
  • ^([가-힣]+[0-9]*)$ : 한글로 된 문자가 꼭 포함 되어야 하며, 숫자가 있어도 됨
  • ^([가-힣]+[0-9]{0,3})$ : 한글로 된 문자가 꼭 포함 되어야 하며 숫자는 있어도 된다. (숫자의 개수는 3개 제한)
  • \w+@\w+\.\w+(\.\w+)? : 이메일 주소
  • ^\d{2,3}-\d{3,4}-\d{4}$ : 전화번호
  • ^01(?:0|1|[6-9])-(?:\d{3}|\d{4})-\d{4}$ : 핸드폰 번호
  • \d{6} - [1-4]\d{6} : 주민등록 번호
  • ^\d{3}-\d{2}$ : 우편번호

참조