* 정규식이란?
정규식(regular expression: regex)은 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하는 형식 언어이다.
* JAVA 정규식의 사용
정규식은 java.util.regex의 Pattern 과 Matcher 클래스를 주로 이용한다.
Pattern은 말 그대로 어떤 문자열에서 찾을 패턴을 뜻한다.
문자열(String)의 정규식은 먼저 Pattern 인스턴스로 컴파일 되어야 한다. 그런 다음 Matcher를 이용, 일치하는 개체를 만들 수 있다.
일반적인 호출 순서는 다음과 같다.
Pattern p = Pattern.compile("a*b"); // a와 b 사이에 문자가 있을 수도 없을 수도?
Matcher m = p.matcher("aaaaab");
Matcher m2 = p.matcher("ab");
Matcher m3 = p.matcher("acb");
boolean b = m.matches(); // 매치
boolean b2 = m2.matches(); // 매치
boolean b3 = m3.matches(); // 매치
또한 matches 메소드를 이용하여 패턴 매칭을 시킬 수도 있는데, 이는 정규식을 한번만 사용할 때 사용한다.
boolean b = Pattern.matches("a*b", "aaaaab"); // true
matches()는 boolean 타입을 리턴한다.
* 정규식의 메타문자들과 그룹
메타 문자들
우선 \가 붙는 문자는 특수문자(명령어?)임을 나타낸다.
^ : 문자열의 시작을 나타낸다. [] 괄호 안에 쓰이는 경우라면 뒤의 패턴에 일치하지 않기를 나타낸다.
- "^password=": password:password 에는 매칭되지 않고, password=password에는 매칭된다.
- "ab[^0-9]": "ab" 뒤에 숫자가 아니어야 매칭된다. ab22: 매칭 안됨 abc: 매칭 됨
$ : 문자열의 끝 표현
- ERROR$: 문자열이 ERROR로 끝나는 경우에만 매칭된다.
\b : 단어의 경계. 문자열의 시작과 끝, 공백, 개행, 탭, 콤마, 구두점, 대시문자 등이 올 수 있다.
- "\bapple\b" : This is an apple 에는 매칭 되나, This is an pineapple에는 매칭되지 않는다.
\B : \b의 반대
- \bapple\b" : This is an apple 에는 매칭 되지 않으나, This is an pineapple에는 매칭된다.
\s : 공백 문자 및 탭 문자에 매치한다.
\S : 공백 문자가 아닌 한 글자에 매치한다.
\d : 숫자에 매치한다. [0-9]와 같다.
\D : 숫자가 아닌 문자에 매치한다. [^0-9]와 같다.
\w : 단어를 만들 수 있는 글자. 알파벳 대소문자, 숫자, 언더스코어를 포함한다. [A-Za-z0-9_] 와 같다.
\W : \w에 포함되지 않는 문자들
\n : 개행문자. \r은 캐리지 리턴이다.
\ : 이스케이프용 문자. 정규식 상의 특별한 의미가 있는 문자들을 문자 그대로 쓸 때 앞에 붙인다. \^ 라고 쓰면 “^” 문자 그대로를 가리킨다.
. : 아무 문자 1개에 대응된다. 공백 역시 문자 1개로 취급된다.
| : or의 연산을 한다.
그룹
( ( A ) ( B ( C ) ) )에는 4가지 그룹이 있다.
group 1: ( ( A ) ( B ( C ) ) )
group 2: ( A )
group 3: ( B ( C ) )
group 4: ( C)
그룹 0는 언제나 전체 문자열 중에서 패턴이 매칭된 문자열 부분이다.
따라서 매칭된 전체 문자열이 아니라 일부 그룹을 보고싶으면 group(1) 부터 보면 좋다.
그룹의 수는 당연히 표현식마다 달라질 수 있다.
어떤 표현식이 매칭된 문자열의 그룹의 수를 확인하려면 Matcher의 groupCount() 메소드를 사용하면 알 수 있다.
각각의 문자열 그룹을 확인하기 위해선, groupCount() 만큼 for 문을 돌면서 group을 출력하도록 하는 방법 등이 있다.
* 예시
ex1)
- This is a simple question.
- This is a complicated question.
- This is a serious question.
과 같이 simple, complicated, serious 를 stupid 라는 단어로 모두 바꾸고 싶다고 하면 정규식을 어떻게 작성하면 될까?
public class Example {
public static void main(String[] args) {
final String regex = "This is a (.*) question.";
String string = "This is a simple question.\n"
+ "This is a complicated question.\n"
+ "This is a serious question.\n";
final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = pattern.matcher(string);
while (matcher.find()) {
string = string.replace(matcher.group(1), "stupid");
}
System.out.println(string);
}
}
ex2)
- userId=superbono&password=qwerty111&email=email@co.kr
- email=email2@co.kr&userId=superbono&password=qwerty111
- password=qwerty111&userId=superbono&email=email@co.kr
이렇게 입력이 주어질 때, "password=*****"이렇게 password를 가리고 싶다면 어떻게 해야할까?
password=(.*?)&|password=(.*?)$
* 정규식 공부하기 좋은 사이트
정규식 사이트는 여러 곳이 있지만 개인적으로는 이 곳이 제일 좋다.
우선 직관적인 인터페이스와 왼쪽의 code generator를 누르면 작성하려는 언어에 맞게 간단한 예시 코드도 작성해준다. match 되는 그룹에 대해서도 직관적으로 알 수 있어서 애용하고 있다.
저장을 하면 다른 사람들과 공유할 수도 있어, 막혔을 때 저장한 뒤 링크를 보내 누군가에게 물어보기도 편하다.
https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html
'JAVA' 카테고리의 다른 글
JVM의 메모리 구조 (1) | 2022.07.13 |
---|---|
if-else 과 switch 어느 것이 효율적일까? (0) | 2022.02.25 |
Exception (예외) (0) | 2022.02.13 |
IntelliJ 단축키 설정 (0) | 2021.11.30 |
Call By Value / Call By Reference (0) | 2021.08.14 |