정규식?
정규식은 텍스트 데이터 중에서 원하는 조건과 일치하는 문자열을 찾아 내기 위해 사용되는 것이다.
원래는 Unix에서 사용하던 것이었지만 요즘은 다양한 언어에서 지원하고 있다.
정규식을 이용하면 많은 양의 텍스트에서 원하는 데이터를 쉽게 뽑아내거나
입력된 데이터가 맞는지 검증할 수도 있다.
예를 들어 문서에서 전화번호, 이메일, 주소등을 따로 뽑아내거나
사용자가 입력한 비밀번호의 형식이 숫자, 영문의 조합인지 검증이 가능하다.
정규식 패턴 | 설 명 | 결과 |
c[a-z]* | c로 시작하는 영단어 | c, ca, car, combat, count |
c[a-z] | c로 시작하는 두자리 영단어 | ca, co |
c[a-zA-Z] | c로 시작하는 두자리 영단어 (a~z 또는 A~Z 대소문자 구문 안함) |
cA, ca, co |
c[a-zA-Z0-9] c\w |
c로 시작하고 숫자와 영어로 조합된 두 글자 | cA, ca, co, c0 |
.* | 모든 문자열 | bat, baby, bonus, c, cA, ca, c, o, c. c0, c#, car, combat, count, disc |
c. | c로 시작하는 두자리 문자열 | cA, ca, co, c., c0, c# |
c.* | c로 시작하는 모든 문자열(기호포함) | c, cA, ca, c, o, c., c0, c# car, combat, count |
c\. | c와 일치하는 문자열'.'은 패턴작성에 사용되는 문자이므로 escape문자일 '\'를 사용해야한다. |
c. |
c\d c[0-9] |
c와 숫자로 구성된 두자리 문자열 | c0, |
c.*t | c로 시작하고 t로 끝나는 모든 문자열 | combat, count |
[b|c].* [bc].* [b-c].* |
b 또는 c로 시작하는 문자열 | bat, baby, bonus, c, cA, ca, co c., c0, c#, car, combat, count |
[^b|c].* [^bc].* [^b-c].* |
b 또는 c로 시작하지 않는 문자열 | data, disc |
.*a.* | a를 포함하는 모든 문자열 | bat, baby, ca, car, combat, date |
.*a.+ | a를 포함하는 모든 문자열. +: 1또는 그 이상의 문자. +는 * 과 달리 반드시 하나 이상의 문자가 있어야 하므로 a로 끝나는 단어는 포함되지 않았다. |
bat, baye, car, combat, date |
[b|c].{2} | b 또는 c로 시작하는 세자리 문자열. (b 또는 c 다음에 두자리 이므로 모두 세자리) |
bat, car |
0\\d{1, 2} | 0으로 시작하는 최소 2자리 최대 3자리 숫자(0포함) | 00, 01, 02, 000, 001 ,099 |
\\d{3, 4} | 최소 3자리 최대 4자리의 숫자 | 123, 987, 9999, 0000 |
\\d{4} | 4자리의 숫자 | 0000, 1111, 9999 |
사용법 Pattern과 Matcher
사용을 하려면 Pattern클래스와 Matcher클래스를 이용해야 한다.
이름에서 알 수 있듯이 Pattern은 원하는 정규식을 정의해주고
비교대상이 Matcher는 정해진 정규식 조건에 맞는지 비교해준다.
String[] data = {"bat", "baby", "bonus", "cA", "ca", "co", "c.", "c0", "car", "combat", "count", "date", "disc"};
Pattern p = Pattern.compile("c[a-z]*"); // c로 시작하는 소문자영단어
for(int i=0; i < data.length ; i++) {
Matcher m = p.matcher(data[i]);
if(m.matches()) {
System.out.println(data[i]);
}
}
결과
ca
co
car
combat
count
위 코드의 과정을 보자면
1. Pattern클래스의 static메서드인 Pattern compile(String 정규식)을 호출하여 Pattern 인스턴스를 얻는다.Pattern p = Pattern.compile("c[a-z]*");
2. 정규식을 정의해둔 인스턴스 p와 비교할 대상을 메소드 p.matcher(비교대상)로 받아
클래스 Matcher의 인스턴스를 얻는다.Matcher m = p.matcher(data[i]);
3. Matcher인스턴스에 boolean matches()를 호출해서 정규식과 비교한다.if(m.matches())
정규식 그룹화
정규식을 괄호로 나누어 묶으면 그룹화를 할 수 있다.
String source = "HP:011-1111-1111, HOME:02-999-9999";
String pattern = "(0\\d{1,2})-(\\d{3,4})-(\\d{4})";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(source);
int i = 0;
while(m.find()) {
System.out.println( ++i + ": " + m.group() + " -> " + m.group(1) + ", " + m.group(2) + ", " + m.group(3));
}
1: 011-1111-1111 -> 011 , 1111 , 1111
2: 02-999-9999 -> 02 , 999 , 9999
(0\\d{1,2})-(\\d{3,4})-(\\d{4})
괄호를 이용하여 정규식을 세 부분으로 나누었다
첫 번째 그룹은 group(1) 두 번째 그룹은 group(2) 세 번째 그룹은 group(3)으로 호출하여 얻을 수 있다.
그냥 group(), group(0)은 전체를 나누어지지 않은 채로 반환한다.find()
는 주어진 소스에서 패턴과 일치하는 부분이 발견되면 true, 아니면 false를 반환한다.
String source = "A broken hand works, but not a broken heart.";
String pattern = "broken";
StringBuilder sb = new StringBuilder();
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(source);
System.out.println("source : " + source);
int i = 0;
while(m.find()) {
System.out.println(++i + "번째 매칭:" + m.start() + "~" + m.end());
m.appendReplacement(sb, "drunken");
}
m.appendTail(sb);
System.out.println("Replacement count : " + i);
System.out.println("result : "+sb.toString());
source : A broken hand works, but not a broken heart.
1번째 매칭:2~8
2번째 매칭:31~37
Replacement count : 2
result : A drunken hand works, but not a drunken heart.
1. 문자열 source에서 "broken"을 m.find()로 찾으면 m.appendReplacement(sb, "drunken") 이 실행된다.sb에 저장된 내용 : "A drunken"
2. m.find()는 첫 발견 위치에서부터 검색을 시작해서 두번째 "broken"을 찾게되고
m.appendReplacement(sb, "drunken") 이 실행된다.sb에 저장된 내용 : "A drunken hand works, but not a dunken"
3. m.appendTail(sb)가 호출되면서 마지막으로 치환된 이후의 부분을 sb에 붙인다.sb에 저장된 내용 : "A drunken hand works, but not a dunken heart."
댓글