티스토리 뷰
예제 코드는 모두 Java 언어를 사용한다.
앞서 정규 표현식 패턴은 문자 하나만 찾는 패턴만 살펴보았다.
이제 문자를 여러 개 찾는 방법을 살펴볼 예정이다.
하나 이상의 문자 찾기
문자나 집합에 속한 요소를 하나 이상 찾으려면 간단히 문자 뒤에 더하기(+) 문자를 붙이면 된다.
더하기(+)는 문자가 하나 이상일 때 일치한다.
public class code {
public static void main(String[] args) {
String regex = "a[0-9]+";
Pattern pattern = Pattern.compile(regex);
String[] strs = {
"a",
"a1",
"a12",
"1a"
};
for(String str : strs) {
Matcher matcher = pattern.matcher(str);
if (matcher.find()) {
System.out.println("str 안에 " + regex + " 문자열이 존재한다.");
} else {
System.out.println("str 안에 " + regex + " 문자열이 존재하지 않는다.");
}
}
}
}
/*
str 안에 a[0-9]+ 문자열이 존재하지 않는다.
str 안에 a[0-9]+ 문자열이 존재한다.
str 안에 a[0-9]+ 문자열이 존재한다.
str 안에 a[0-9]+ 문자열이 존재하지 않는다.
*/
더하기(+) 문자 역시 메타 문자이므로 문자 그대로 더하기(+)를 찾으려면 역슬래시로 이스케이프해야 한다.
문자가 없거나 하나 이상 연속하는 문자 찾기
더하기(+)는 하나 이상 연속된 문자만 찾는다.
❓ 만약 있을 수도 있고 없을 수도 있는 문자를 찾으려면 어떻게 해야할까?
바로 메타 문자인 별표(*)를 사용하면 된다.
별표(*)는 더하기(+)와 비슷하게 사용된다.
public class code {
public static void main(String[] args) {
String regex = "a[0-9]*";
Pattern pattern = Pattern.compile(regex);
String[] strs = {
"a",
"a1",
"a12",
"1a"
};
for(String str : strs) {
Matcher matcher = pattern.matcher(str);
if (matcher.find()) {
System.out.println("str 안에 " + regex + " 문자열이 존재한다.");
} else {
System.out.println("str 안에 " + regex + " 문자열이 존재하지 않는다.");
}
}
}
}
/*
str 안에 a[0-9]* 문자열이 존재한다.
str 안에 a[0-9]* 문자열이 존재한다.
str 안에 a[0-9]* 문자열이 존재한다.
str 안에 a[0-9]* 문자열이 존재한다.
*/
문자가 없거나 하나인 문자 찾기
문자가 없거나 하나인 문자를 찾으려면 메타 문자로 물음표(?)를 사용하면 된다.
여기서는 책에 좋은 예시가 나와서 책에 있는 예시를 사용해보려고 한다.
http://로 시작하는 URL뿐만 아니라 https://로 시작하는 URL도 가져오고 싶다면 다음과 같은 정규표현식을 사용하면 된다.
⇒ https?:\/\/[\w.\/]+
public class code {
public static void main(String[] args) {
String regex = "https?:\\\\/\\\\/[\\\\w.\\\\/]+";
Pattern pattern = Pattern.compile(regex);
String[] strs = {
"<http://www.naver.com>",
"<https://www.github.com/kkoon9>",
"httpssss://www.github.com/kkoon9"
};
for(String str : strs) {
Matcher matcher = pattern.matcher(str);
if (matcher.find()) {
System.out.println("str 안에 " + regex + " 문자열이 존재한다.");
} else {
System.out.println("str 안에 " + regex + " 문자열이 존재하지 않는다.");
}
}
}
}
/*
str 안에 https?:\\/\\/[\\w.\\/]+ 문자열이 존재한다.
str 안에 https?:\\/\\/[\\w.\\/]+ 문자열이 존재한다.
str 안에 https?:\\/\\/[\\w.\\/]+ 문자열이 존재하지 않는다.
*/
물음표(?) 역시 메타 문자이므로 문자 그대로 찾으려면 역슬래시로 이스케이프해야 한다.
구간 지정하기
다음과 같은 상황을 생각해보자.
- 문자의 최대/최소 개수를 정하고 싶을 때
- 정확히 원하는 개수를 정하고 싶을 때
이런 상황들을 해결하고, 연속하는 문자를 찾을 때 검색 조건을 더 구체적으로 지정할 때 구간을 사용한다.
구간은 중괄호({})안에 표시한다.
먼저 정확한 구간 찾기부터 실습해보자.
public class code {
public static void main(String[] args) {
String regex = "a[0-9]{2}";
Pattern pattern = Pattern.compile(regex);
String[] strs = {
"a1",
"a12",
"a123",
"1a"
};
for(String str : strs) {
Matcher matcher = pattern.matcher(str);
if (matcher.find()) {
System.out.println("str 안에 " + regex + " 문자열이 존재한다.");
} else {
System.out.println("str 안에 " + regex + " 문자열이 존재하지 않는다.");
}
}
}
}
/*
str 안에 a[0-9]{2} 문자열이 존재하지 않는다.
str 안에 a[0-9]{2} 문자열이 존재한다.
str 안에 a[0-9]{2} 문자열이 존재한다.
str 안에 a[0-9]{2} 문자열이 존재하지 않는다.
*/
3번째 예시같은 경우는 a123에서 bold 처리된 부분이 존재하므로 존재한다라는 결과값이 나온것이다.
다음은 범위 구간 찾기 실습을 해보자.
전화번호를 예시로 진행하려고 한다.
전화번호 앞자리는 010도 존재하지만 02라는 두글자도 존재한다.
전화번호의 두번째 자리 역시 1111처럼 네자리말고 233같은 세자리도 존재한다.
이걸 정규표현식으로 표현해보자.
public class code {
public static void main(String[] args) {
String regex = "[0-9]{2,3}-[0-9]{3,4}-[0-9]{4}";
Pattern pattern = Pattern.compile(regex);
String[] strs = {
"010-0000-0000",
"02-000-0000",
"0-01304-40245"
};
for(String str : strs) {
Matcher matcher = pattern.matcher(str);
if (matcher.find()) {
System.out.println("str 안에 " + regex + " 문자열이 존재한다.");
} else {
System.out.println("str 안에 " + regex + " 문자열이 존재하지 않는다.");
}
}
}
}
/*
str 안에 [0-9]{2,3}-[0-9]{3,4}-[0-9]{4} 문자열이 존재한다.
str 안에 [0-9]{2,3}-[0-9]{3,4}-[0-9]{4} 문자열이 존재한다.
str 안에 [0-9]{2,3}-[0-9]{3,4}-[0-9]{4} 문자열이 존재하지 않는다.
*/
최소 구간은 {3,}와 같이 콤마 뒤에 아무것도 안써주면 최소 구간을 정할 수 있다.
과하게 일치하는 상황 방지하기
물음표(?)는 제한된 범위만큼 일치시키고, 구간을 쓰면 정확히 지정한 만큼 일치하거나 지정한 범위 안에서만 검색을 수행한다.
다음 예를 살펴보자.
태그 a로 감싸진 모든 값을 출력해고 싶어서 다음과 같이 정규표현식을 사용했다.
public class code {
public static void main(String[] args) {
String regex = "<a>.*</a>";
Pattern pattern = Pattern.compile(regex);
String[] strs = {
"<a>kkoon9</a> <a>kkoon9_e</a>"
};
int count = 1;
for(String str : strs) {
Matcher matcher = pattern.matcher(str);
while(matcher.find()) {
System.out.println(count++ + ". : " + matcher.group());
}
}
}
}
/*
1. <a>kkoon9</a> <a>kkoon9_e</a>
*/
하지만 결과는 전체적으로 묶인 한줄의 결과만 나오게 된다.
바로 별표(*)와 더하기(+) 같은 메타 문자가 탐욕적(greedy)이므로 이는 가능한 한 가장 큰 덩어리를 찾으려 한다는 뜻이다.
이런 메타 문자는 찾으려는 텍스트를 앞에서부터 찾는 게 아니라, 텍스트 마지막에서 시작해 거꾸로 찾는다.
의도적으로 수량자를 탐욕적으로 설계했기 때문이다.
❓ 탐욕적 일치를 원하지 않는다면 어떻게 해야 할까?
탐욕적 수량자를 게으른(lazy) 수량자로 바꿔 이 문제를 해결할 수 있다.
‘게으른’이라고 부르는 이유는 문자가 최소로 일치하기 때문이다.
탐욕적 수량자 | 게으른 수량자 |
* | *? |
+ | +? |
{n,} | {n,}? |
위 코드를 게으른 수량자로 바꿔보자.
public class code {
public static void main(String[] args) {
String regex = "<a>.*?</a>";
Pattern pattern = Pattern.compile(regex);
String[] strs = {
"<a>kkoon9</a> <a>kkoon9_e</a>"
};
int count = 1;
for(String str : strs) {
Matcher matcher = pattern.matcher(str);
while(matcher.find()) {
System.out.println(count++ + ". : " + matcher.group());
}
}
}
}
/*
1. : <a>kkoon9</a>
2. : <a>kkoon9_e</a>
*/
'개발 방식 연구 > 정규표현식' 카테고리의 다른 글
정규표현식 [7] 역참조 (0) | 2022.01.08 |
---|---|
정규표현식 [6] 위치 찾기 (0) | 2022.01.08 |
정규표현식 [4] 메타 문자 (0) | 2022.01.08 |
정규표현식 [3] 문자 집합으로 찾기 (0) | 2022.01.08 |
정규표현식 [2] 문자 하나 찾기 (0) | 2022.01.08 |
- Total
- Today
- Yesterday
- 디자인 패턴
- JPA
- MSA
- Java
- BOJ
- 코테
- 백준
- Olympiad
- Spring Boot
- 프로그래머스
- Kotlin
- kkoon9
- Algorithm
- kotest
- AWS
- 이팩티브 자바
- 클린 아키텍처
- Effective Java
- 디자인패턴
- 테라폼
- 클린 코드
- 정규표현식
- C++
- node.js
- BAEKJOON
- 객체지향
- programmers
- Spring
- 이펙티브 자바
- 알고리즘
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |