[Java] 정규표현식과 Pattern/Matcher

승등·2023년 10월 29일
0

Java

목록 보기
4/4

📒 정규표현식


정규표현식(Regular Expression, regex) 또는 정규식은 특정한 규칙을 가진 문자열의 집합을 표현하기 위해 쓰이는 형식언어다.

컴퓨터 과학의 정규 언어로부터 유래하였으며 현재 많은 프로그래밍 언어, 텍스트 처리 프로그램, 고급 텍스트 편집기 등이 정규 표현식 기능을 제공한다.

자바의 경우 표준 라이브러리를 통해 제공한다.

정해진 형식이 존재하는 문자열(전화번호, 주민등록번호, 이메일등)의 검증 등에 정규표현식을 사용하면 쉽게 구현할 수 있다.

🔖 정규식 문법

문자 클래스 (Character classes)

  • 문자 클래스는 문자 패턴을 찾을 때 사용
  • 어떠한 문자가 포함된다, 포함되지 않는다. 어떤 문자만 찾는다 등등 문자 패턴을 구성할 때 사용
기호설명예제
.임의의 문자 1개를 의미.{3} : 문자 3개 (F15,0x0등)
\w알파벳 대소문자, 숫자, 언더바. [a-zA-Z_0-9]와 동일.
\d모든 ASCII 숫자. [0-9]와 동일
\s모든 유니코드 공백 문자. [\t\n\x0B\f\r]
\W\w를 제외한 모든 문자. [^a-zA-Z_0-9]
\D\d를 제외한 모든 문자. [^0-9]
\S\s를 제외한 모든 문자. [^\t\n\x0B\f\r]
[ ]대괄호 내부의 문자가 있는지 확인[ab][cd] : a,b중 한 문자와 c,d중 한 문자
→ ac ad bc bd
[^]대괄호 내 ^는 제외를 의미[^a-z] : 알파벳 소문자 a부터 z까지를 제외한 모든 문자
-숫자 또는 문자 사이에서 사용하여 범위를 지정[a-z] : 알파벳 소문자 a부터 z까지 하나
[a-z0-9] : 알파벳 소문자 전체,0~9 중 한 문자

한글의 경우 /w에 포함되지 않으므로 아래와 같이 따로 작성해주어야 한다.

기호설명예제
[ㄱ-ㅎㅏ-ㅣ]한글 자,모음
[가-힣]가~힣 까지 한글

앵커 (Anchors)

  • 앵커는 정규식 패턴 맨 앞과 맨 뒤에 위치하며, 정규식 매치 위치를 고정하는데 사용.
기호설명예제
^정규식으로 검증하는 문자열의 시작을 의미^a : a로 시작하는 단어
$정규식으로 검증하는 문자열의 끝을 의미a$ : a로 끝나는 단어
\b단어의 경계. 문자열의 시작과 끝, 공백, 개행, 탭, 콤마, 구두점, 대시문자 등"\bapple\b" :
This is an apple (o)
This is an pineapple(x)
\B\B의 반대

그룹 (group)

  • 정규식의 일부 패턴을 하나로 그룹화 할 수 있다.
  • 정규식 그룹은 번호가 매겨진 캡처 그룹을 생성하고, 괄호 안에 정규식 부분과 일치하는 문자열을 저장.
  • (?<그룹이름>정규식패턴)의 구조로 그룹에 이름을 붙일 수도 있다.
  • 저장된 문자열은 그룹번호 또는 이름으로 불러올 수 있다.
  • 캡쳐에는 정규식으로 찾은 문자열이 저장되는 것이지 정규식 자체가 저장되는 것이 아니다. ("(\w+)\s\1"gm → abc abc(o), abc def(x))
기호설명예제
( )괄호 안을 하나의 그룹으로 묶는다.01(0|1) : 01뒤에 0 또는 1이 들어간다
→ 010(o), 011(o), 012(x)
\n그룹n의 캡쳐를 사용"(regex)\s\1"gm → regex regex(o)
(?: )캡쳐를 사용하지 않는 그룹

전후방탐색자 (Lookaround)

  • 앞뒤에 지정한 문자가 오는 특정 문자를 찾을 때 사용
기호이름설명
X(?=Y)긍정형 전방탐색(Positive lookahead)뒤에 Y가 오는 X
X(?!Y)부정형 전방탐색(Negative lookahead)뒤에 Y가 오지 않는 X
(?<=Y)X긍정형 후방탐색(Positive lookbehind)Y 다음으로 오는 X
(?<!Y)X부정형 후방탐색(Negative lookbehind)Y 다음으로 오지 않는 X

수량자 (Quantifiers)

  • 어떤 정규식 패턴이 얼마나 반복되는지에 대한 패턴을 정의할 때 사용
기호설명예시
X*X가 0개 또는 그 이상 존재
X+X가 1개 또는 그 이상 존재
X?X가 0개 또는 1개 존재
X{n}X가 정확히 n개 존재
X{n,m}X가 n개 이상 m개 이하 존재
X{2, }X가 2개거나 그 이상 존재

플래그 (Flag)

  • 정규식 검색 옵션을 설정하는 문법
  • 기호 혹은 상수로 표현 할 수 있다.
// 정규식 기호로 전달
Pattern.compile("(?i)([a-z]+)")

// 상수로 전달
Pattern.compile("(^.*$)", Pattern.CASE_INSENSITIVE)
기호상수설명
(?i)Pattern.CASE_INSENSITIVE대소문자를 구분하지 않고 검색
(?m)Pattern.MULTILINE문자열의 행이 여러개일 경우 행 별로 구분해서 패턴을 검색
(?s)Pattern.DOTALL.가 개행문자 까지 포함하는 모든 문자로 매칭
(?u)Pattern.UNICODE_CASE유니코드 패턴을 사용

📒 Pattern 클래스


  • Pattern클래스는 정규 표현식에 대상 문자열을 검증하거나, 활용하기 위해 사용되는 클래스

🔖 주요 메소드

리턴 타입메소드설명
static Patterncompile(String regex)주어진 정규식을 갖는 Pattern을 생성
Pattern pattern = Pattern.compile(regex); 형태로 사용
Stringpattern()컴파일된 정규 표현식을 반환
Matchermatcher(CharSequence input)패턴에 매칭할 문자열을 입력해 Matcher를 생성
Matcher matcher = pattern.matcher(input); 형태로 사용
static booleanmatches(String regex, CharSequence input)정규식과 문자열이 일치하는지 확인
String[]split(CharSequence input)패턴이 일치하는 항목을 중심으로 input을 분할
String[]split(CharSequence input, int limit)위와 동일한 방식으로 문자열을 limit회 만큼 분할(문자열이 limit개 생성) 만약 0이하라면 최대한 많이 적용

📒 Matcher 클래스


  • Pattern클래스를 받아 대상 문자열과 패턴이 일치하는 부분을 찾거나 전체 일치 여부 등을 판별하기 위해 사용되는 클래스

🔖 주요 메소드

리턴 타입메소드설명
Patternpattern()matcher가 해석한 패턴을 반환
MatcherusePattern(Pattern newPattern)matcher가 사용할 Pattern을 변경
Matcherreset(CharSequence input)matcher가 분석할 문자열을 변경
intstart()매칭하는 문자열의 시작 인덱스를 반환
intstart(int group)매칭 문자열 중 group번째 문자열의 시작 인덱스를 반환
0은 그룹의 전체 패턴을 의미 start(0) = start()
intstart(String name)매칭 문자열 중 해당 name을 지정한 그룹의 시작 인덱스를 반환
intend()일치하는 문자열의 마지막 문자열 이후 인덱스를 반환
intend(int group)매칭 문자열 중 group번째 그룹의 마지막 문자열 이후(+1) 인덱스를 반환
0은 그룹의 전체 패턴을 의미 end(0) = end()
intend(String name)매칭 문자열 중 해당 name을 지정한 그룹의 마지막 문자열 이후(+1) 인덱스를 반환
Stringgroup()매치와 일치하는 문자열을 반환
Stringgroup(int group)매칭되는 문자열 중 group번째 그룹의 문자열 반환
0은 그룹의 전체 패턴을 의미 group(0) = group()
Stringgroup(String name)매칭되는 문자열 중 해당 name을 지정한 그룹의 문자열 반환
intgroupCount()패턴 내에 그룹핑한 개수를 반환(패턴에 있는 괄호 개수)
booleanmatches()패턴에 전체 문자열이 일치한 경우 true를 반환
booleanfind()패턴이 일치하는 다음 문자열을 찾는다. 다음 문자열이 있다면 true
booleanfind(int start)start 인덱스 이후부터 패턴에 일치하는 문자열을 찾는다
StringreplaceAll(String replacement)패턴과 일치하는 모든 문자열을 지정된 replacement로 변경

📒 예시

🔖 일치여부 판별

String regex1 = "^[a-zA-Z]+$"; // 알파벳 대소문자
String regex2 = "^[\\w]+$"; // 알파벳 대소문자, 숫자, 언더바

String input1 = "test TEST";
String input2 = "testTEST";
String input3 = "test 1234";
String input4 = "test1234";

System.out.println(Pattern.matches(regex1, input1)); // false
System.out.println(Pattern.matches(regex1, input2)); // true
System.out.println(Pattern.matches(regex1, input3)); // false
System.out.println(Pattern.matches(regex1, input4)); // false

System.out.println(Pattern.matches(regex2, input1)); // false
System.out.println(Pattern.matches(regex2, input2)); // true
System.out.println(Pattern.matches(regex2, input3)); // false
System.out.println(Pattern.matches(regex2, input4)); // true
  • \w에 공백문자는 포함되지 않기 때문에 input1,3 는 false가 출력된다.

🔖 패턴 생성

String regex = "^[\\S]+$"; // 공백문자를 제외한 모든 문자
String input1 = "test 1234 !@#$";
String input2 = "test1234!@#$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher1 = pattern.matcher(input1);
Matcher matcher2 = pattern.matcher(input2);

System.out.println(pattern.pattern()); // ^[\S]+$
System.out.println(matcher1.pattern()); // ^[\S]+$

System.out.println(matcher1.matches()); // false
System.out.println(matcher2.matches()); // true

🔖 플래그

String regex1 = "^.*$"; // 임의의 문자(개행문자를 제외한 모든 문자)
String regex2 = "(?s)^.*$"; // 개행문자 포함 모든 문자
String input = "test\n1234\n!@#$";

Pattern pattern1 = Pattern.compile(regex1);
Pattern pattern2 = Pattern.compile(regex2);
Matcher matcher1 = pattern1.matcher(input);
Matcher matcher2 = pattern2.matcher(input);

System.out.println(matcher1.matches()); // false
System.out.println(matcher2.matches()); // true

🔖 그룹

그룹화

  • 소괄호( )를 사용하여 패턴을 하나의 그룹으로 묶을 수 있다.
  • 묶은 그룹에 이름을 붙여 사용 할 수 있다.
String regex1 = "([a-zA-Z]+)([0-9]*)([*!@#]?)";
String regex2 = "(?<alphabet>[a-zA-Z]+)(?<digit>[0-9]*)(?<symbol>[*!@#]?)";

String input = "abc0!A999AbC#!";

Pattern pattern1 = Pattern.compile(regex1);
Matcher matcher1 = pattern1.matcher(input);

Pattern pattern2 = Pattern.compile(regex2);
Matcher matcher2 = pattern2.matcher(input);
  • 정규식 그룹은 번호가 매겨진 캡처 그룹을 생성하고, 괄호 안에 정규식 부분과 일치하는 문자열을 저장한다.
  • 매겨진 번호와 group()메소드를 이용하여 사용하여 저장한 문자열을 출력할 수 있다.
while(matcher1.find()) { // 일치하는 다음 패턴이 있는동안 반복
  System.out.println(matcher1.group());
}
// abc0!
// A999
// AbC#

while(matcher1.find()) { // 일치하는 다음 패턴이 있는동안 반복
  System.out.println(matcher1.group(1) + "/" + matcher1.group(2) + "/" + matcher1.group(3));
}
// abc/0/!
// A/999/
// AbC//#

while(matcher1.find()) { // 일치하는 다음 패턴이 있는동안 반복
  System.out.println("시작 인덱스: " + matcher1.start(1) + "/" + matcher1.start(2) + "/" + matcher1.start(3));
  System.out.println("마지막 인덱스: " + matcher1.end(1) + "/" + matcher1.end(2) + "/" + matcher1.end(3));
  System.out.println("");
}
// 시작 인덱스: 0/3/4
// 마지막 인덱스: 3/4/5
//
// 시작 인덱스: 5/6/9
// 마지막 인덱스: 6/9/9
//
// 시작 인덱스: 9/12/12
// 마지막 인덱스: 12/12/13
  • 그룹 번호 대신에 붙인 이름을 사용할 수도 있다.
 while(matcher2.find()) { // 일치하는 다음 패턴이 있는동안 반복
    System.out.println(matcher2.group("alphabet") + "/" + matcher2.group("digit") + "/" + matcher2.group("symbol"));
}
//        // abc/0/!
//        // A/999/
//        // AbC//#

while(matcher2.find()) { // 일치하는 다음 패턴이 있는동안 반복
    System.out.println("시작 인덱스: " + matcher2.start("alphabet") + "/" + matcher2.start("digit") + "/" + matcher2.start("symbol"));
    System.out.println("마지막 인덱스: " + matcher2.end("alphabet") + "/" + matcher2.end("digit") + "/" + matcher2.end("symbol"));
    System.out.println("");
}
//        시작 인덱스: 0/3/4
//        마지막 인덱스: 3/4/5
//
//        시작 인덱스: 5/6/9
//        마지막 인덱스: 6/9/9
//
//        시작 인덱스: 9/12/12
//        마지막 인덱스: 12/12/13

Reference

배워보자 정규표현식! (Regular Expression)
자바 정규식(Regular Expression) 사용법 💯 정리
[Java] Pattern, Matcher Class 사용법과 메소드 정리

0개의 댓글