자바 (18). 정규 표현식과 정규식을 지원하는 String 메서드 & Pattern, Matcher
봐도봐도 또 기억안나는 정규표현식 이번엔 완벽히,, 정리해보자
0. 목차
- 정규 표현식이란?
- 정규표현식 정
- 정규식을 지원하는 String 메서드
- java.util.regex.Pattern
- java.util.regex.Matcher
- 재미있는 예제 anagram
1. 정규 표현식(Regular Expression)이란?
정규 표현식이란 컴퓨터 과학의 정규언어로 부터 유래한 것으로 특정한 규칙을 가진 문자열의 집합을 표현하기 위해 쓰이는 형식 언어이다.
2-1. 정규표현식 정리
정규 표현식에서 사용되는 기호를 Meta문자라 하고, 표현식에서 내부적으로 특정 의미를 가지는 문자를 말한다.
- ^ : 문자열의 시작
- ex) ^x : 문자열의 시작을 표현하며 x문자로 시작됨
- $ : 문자열의 종료
- ex) x$ : 문자열의 종료를 표현하며 x문자로 종료됨
- . : 임의의 한 문자 (문자의 종류 가리지 않음)
- ex) .x : 임의의 한 문자의 자리수를 표현하며 문자열이 x로 끝남을 의미
- * : 앞 문자가 없을 수도 무한정 많을 수도 있다.
- ex) x* : 반복여부를 표현하며 x문자가 0번 또는 그 이상 반복됨을 의미,
- + : 앞 문자가 하나 이상 존재 해야 한다.
- ex) x+ : 반복을 표현하며, x문자가 한번 이상 반복됨을 의미
- ? : 앞 문자가 없거나 하나 있다.
- ex) x? : 존재여부를 표현하며 x문자가 존재할수도 있고 없을 수 도 있다.
- [] : 문자의 집합이나 범위를 나타내며 두문자 사이는 - 기호로 범위를 나타낸다. []내에서 ^가 선행하여 존재하면 not을 나타낸다.
- ex1) [xy] : 문자 선택을 표혀하며 x와 y중에 하나를 의미
- ex2) [^xy] : not을 표현하며 x 및 y를 제외한 문자를 의미
- ex3) [x-y] : range를 표현하며 x~z 사이의 문자를 의미
- {} : 횟수 또는 범위를 나타낸다.
- ex1) x{n} : 반복을 표현하며 x문자가 n번 반복됨을 의미
- ex2) x{n,} : 반복을 표현하며 x문자가 n번 이상 반복됨을 의미
- ex3) x{n,m} : 반복을 표현하며 x문자가 최소 n번이상 최대 m번 이하로 반복됨을 의
- () : 소괄호 안의 문자를 하나의 문자로 인식한다.
- ex1) (x) : 그룹을 표현하며 x 를 그룹으로 처라함을 의미
- ex2) (x)(y) : 그룹들의 집합을 표현하며 앞에서 부터 순서대로 번호를 부여 하여 관리, x, y는 각 그룹의 데이터로 관리
- ex3) (x)(?:y) : 그룹들의 집합에 대한 예외를 표현하며 그룹 집합으로 관리되지 않음을 의미
-
: 패턴 안에서 or 연산을 수행할 때 사용 -
x y : or를 표현하며 x 또는 y문자가 존재함을 의미
-
- \s : 공백 문자
- \S : 공백 문자가 아닌 나머지 문자
- \w : 알파벳이나 숫자
- \W : 알파벳이나 숫자를 제외한 문자
- \d : 숫자 0~9
- \D : 숫자를 제외한 모든 문자
- \ : 정규 표현식 역슬래시 ())는 확장 문자, 역슬래시 다음에 일반 문자가 오면 특수 문자로 취급하고, 역슬래시 다음에 특수문자가 오면 그 문자 자체를 의미한다.
- (?i) : 앞 부분에 (?i) 라는 옵션이 있으면 대소문자를 구분하지 않는다.
2-2. 정규식 사용 방법
^[0-9]*$ 를 뜯어 보자
- ^ 으로 우선 패턴의 시작을 알린다.
- [0-9] 괄호사이에 두 숫자를 넣어 범위를 지정
-
- 를 넣어 글자의 수를 상관하지 않고 검사한다.
- $ 으로 패턴의 종료를 알림
즉 위의 예제는 0~9 까지의 숫자를 글자 수를 제한하지 않고 검사하는 패턴이다.
2-3. 문자 정규식
- [abc] : a 또는 b 또는 c 중 하나
- [^abc] : a, b, c가 아닌 문자 중 하나
- [a-zA-z] : 알파벳 중 하나
- [a-d[m-p]] : a에서 d혹은 m에서 p 까지 중 하나
- [a-z&&[def]] : d 또는 e 또는 f 중 하나
- [a-z&&[^bc]] : a에서 z 중 b 와 c를 제외한 문자 하나
- [a-z&&[^m-p]] : a에서 z 중 m 에서 p를 제외한 문자 하
2-4. 자주 사용하는 정규 표현식
숫자만 가능 : [ 0 ~ 9 ] 주의 : 띄어쓰기 불가능
- /^[0-9]+$/
이메일 형식만 가능
- /^([\w-]+(?:.[\w-]+))@((?:[\w-]+.)\w[\w-]{0,66}).([a-z]{2,6}(?:.[a-z]{2})?)$/
한글만 가능 : [ 가나다라 … ] 주의 : ㄱㄴㄷ… 형식으로는 입력 불가능 , 띄어쓰기 불가능
- /^[가-힣]+$/
한글,띄어쓰기만 가능 : [ 가나다라 … ] 주의 : ㄱㄴㄷ… 형식으로는 입력 불가능 , 띄어쓰기 가능
- /^[가-힣\s]+$/
영문만 가능 :
- /^[a-zA-Z]+$/
영문,띄어쓰기만 가능
- /^[a-zA-Z\s]+$/
전화번호 형태 : 전화번호 형태 000-0000-0000 만 받는다. ]
- /^[0-9]{2,3}-[0-9]{3,4}-[0-9]{4}$/
도메인 형태, http:// https:// 포함안해도 되고 해도 되고
- /^(((http(s?)):\/\/)?)([0-9a-zA-Z-]+.)+[a-zA-Z]{2,6}(:[0-9]+)?(\/\S*)?$/
도메인 형태, http:// https:// 꼭 포함
- /^((http(s?)):\/\/)([0-9a-zA-Z-]+.)+[a-zA-Z]{2,6}(:[0-9]+)?(\/\S*)?$/
도메인 형태, http:// https:// 포함하면 안됨
- /^[^((http(s?)):\/\/)]([0-9a-zA-Z-]+.)+[a-zA-Z]{2,6}(:[0-9]+)?(\/\S*)?$/
한글과 영문만 가능
- /^[가-힣a-zA-Z]+$/;
숫자,알파벳만 가능
- /^[a-zA-Z0-9]+$/;
주민번호, -까지 포함된 문자열로 검색
-
/^(?:[0-9]{2}(?:0[1-9] 1[0-2])(?:0[1-9] [1,2][0-9] 3[0,1]))-[1-4][0-9]{6}$/
3. 정규식을 지원하는 String 메서드
String 클래스에는 Regex를 지원하는 메소드들이 있다.
- String.matches(regex) : String이 regex와 일치하면 true 리턴
- String.split(regex) : regex와 일치하는 것을 기준으로 String을 분리하여 배열로 리턴
- String.replaceFirst(regex, replacement) : regex와 가장 먼저 일치하는 것을 replacement로환 변환
- String.replaceAll(regex, replacement) : regex와 일치하는 모든 것을 replacement로 변
public class example {
public static void main(String[] args) {
// 1. .은 문자 한개에 해당한다.
String pattern = "ab.";
System.out.println("abc".matches(pattern));
System.out.println("ab ".matches(pattern)); // whitespace 도 문자로 카운트
System.out.println("ab".matches(pattern));
System.out.println("");
// 2. \s 는 whitespace 한개, \S 는 whitespace를 제외한 문자 한개를 의미
pattern = "ab\\s\\S";
System.out.println("ab ".matches(pattern));
System.out.println("ab c".matches(pattern));
// 3. ^는 문자열의 시작지점을 찾는다. 따라서 ^ 다음으로 오는 패턴으로 문자열이 시작되는 것을 찾는다.
// 아래 regex와 일치하는 내용을 replacement로 교체 한다. 결과에서 * 로 변경된 내용이 regex와 일치하는 것이라고 생각한다.
String result = "The cat sat on the mat.".replaceAll("[Tt]he", "*");
System.out.println(result);
result = "The cat sat on the mat.".replaceAll("^[Tt]he", "*");
System.out.println(result);
// 4. $는 문자열의 종료 지점을 찾는다. 따라서 $ 앞 패턴으로 문자열이 끝나는 것을 찾는다.
result = "The cat sat on the mat. and the cat".replaceAll("cat", "*");
System.out.println(result);
result = "The cat sat on the mat. and the cat".replaceAll("cat$", "*");
System.out.println(result);
// 5. \b 는 단어의 경계선을 찾는 역할을 한다. 단여 양옆에 \b를 사용하여 다른 문자와 결합되지 않은, 독립적인 단어를 찾을 수 있다.
result = "This island is beautiful.".replaceAll("is", "*");
System.out.println(result);
result = "This island is beautiful".replaceAll("\\bis\\b", "*");
System.out.println(result);
// 6. []는 내부의 문자열과 일치하는 문자 1개를 찾는다. -를 사용하면 범위 또한 지정이 가능하다.
pattern = "[abc][vz]";
System.out.println("av".matches(pattern));
System.out.println("cz".matches(pattern));
System.out.println("ac".matches(pattern));
pattern = "Ex_[a-g1-5]";
System.out.println("Ex_g".matches(pattern));
System.out.println("Ex_6".matches(pattern));
// 숫자, 문자, 공백을 표현하는 Metacharacters들에 대한 예제. 자바는 \를 표현하기 위해선 \\로 입력을 해야 한다.
pattern = "\\d\\D";
System.out.println("1a".matches(pattern));
System.out.println("a1".matches(pattern));
System.out.println("11".matches(pattern));
pattern = "\\d\\s\\D";
System.out.println("1 a".matches(pattern));
pattern = "\\d\\s\\d\\D";
System.out.println("1 1a".matches(pattern));
pattern = "\\d\\s\\S\\D";
System.out.println("1 1a".matches(pattern));
pattern = "\\w\\W";
System.out.println("1 ".matches(pattern));
// Quantifiers
// *, +, ?, {}, *?
// * 은 * 앞의 요소가 0번 이상 반복되는 것을 의미
pattern = "a*[0-9]*";
System.out.println("aaa123".matches(pattern));
System.out.println("aaa".matches(pattern));
// + 은 + 앞의 요소가 1번 이상 반복되는 것을 의미
pattern = "a+[0-9]+";
System.out.println("aaa123".matches(pattern));
System.out.println("aaa".matches(pattern));
// ? 은 요소가 0 또는 1회만 반복되는 것을 의미
pattern = "a*[0-9]?";
System.out.println("aaa".matches(pattern));
System.out.println("aaa12".matches(pattern));
// {x,y} 는 x,y 사이의 수만큼 반복된 다는것을 의미, 위에서 문자열 1개로 처리했던 것을 모두 표현 가능
pattern = "a*[0-9]{2,3}";
System.out.println("aaa".matches(pattern));
System.out.println("aaa12".matches(pattern));
pattern = "a{2,3}[0-9]{2,3}";
System.out.println("aaa12".matches(pattern));
}
}
4. java.util.regex.Pattern
Pattern 객체 정규 표현식에 대상 문자열을 검증하는 기능으로 java.util.regex.Pattern 이 사용된다.
정규식의 컴파일된 표현 (정규식을 적용 가능하도록 컴파일 하여 가지고 있다.) Pattern 클래스는 공개된 생성자를 제공하지 않는다. 패턴을 생성하려면 Pattern 객체를 반환하는 정적 compile 메소드를 호출해야 한다. 이 메소드는 첫 번째 인자로 정규식 문자열을 받아 들인다.
String.matche 와 Pattern.matches
public class PatternEx {
public static void main(String[] args) {
String pattern = "^[0-9]*$";
String val = "123456789";
boolean regex = Pattern.matches(pattern, val);
System.out.println(regex); // true
System.out.println(val.matches(pattern)); // true
}
}
두개의 결과가 같다. 그럼 왜 Pattern 클래스를 사용하는가?? Pattern 클래스는 아래와 같은 기능들을 더 가지고 있다.
Pattern 주요메서드 compile(String regex) : 주어진 정규 표현식으로 부터 패턴을 만든다. matcher(CharSequence input) : 대상 문자열이 패턴과 일치할 경우 true를 반환한다. asPredicate() : 문자열을 일치시키는 데 사용할 수 있는 사술어를 작성한다. pattern() : 컴파일된 정규표현식을 String 형태로 반환한다. split(CharSequence input) : 문자열을 주어진 인자값 CharSequence 패턴에 따라 분리한다.
Pattern 플래그 (상수)값 사용 Pattern.CANON_EQ : None표준화된 매칭 모드를 활성화 Pattern.CASE_INSENSITIVE : 대소문자를 구분하지 않는다. Pattern.COMMENT : 공백과 #으로 시작하는 주석이 무시된다. Pattern.MULTILINE : 수식 ^는 라인 시작, $는 라인의 끝과 매치된다. Pattern.DOTALL : 수식 .과 모든 문자와 match 되고 \n도 match 에 포함된다. Pattern.UNICODE_CAE : 유니코드를 기준으로 대소문자 구분없이 match 시킨다. Pattern.UNIX_LINES : 수식 .과 ^및 $의 match시에 한라인의 끝을 의미하는 \n만 인식된다.
5. java.util.regex.Matcher
6. 예제 anagram
public class Anagram {
public static boolean isAnagram(String s1, String s2) {
// 공백 제거
s1 = s1.replaceAll("\\p{Z}","");
s2 = s2.replaceAll("\\p{Z}","");
if (s1.length() != s2.length()) {
return false;
}
// 소문자로 변환 + char 배열 변환
char[] c1 = s1.toLowerCase().toCharArray();
char[] c2 = s2.toLowerCase().toCharArray();
// Arrays.sort() 오름 차순 정렬
Arrays.sort(c1);
Arrays.sort(c2);
String sc1 = new String(c1);
String sc2 = new String(c2);
if (sc1.equals(sc2)) {
return true;
} else {
return false;
}
}
public static void main(String[] args) {
if(isAnagram("Justin Timberlake", "Im a jerk but listen")) {
System.out.println("These sequence are anagram");
} else {
System.out.println("These sequence are not anagram");
}
}
}
위 코드를 좀 더 똑똑하게 꾸며볼 수 있겠지만 ,, 여기선 그렇게 까지 만들지는…