반응형
정규 표현식이란?
정규 표현식(regular expression)은 특정 규칙을 가진 문자열을 특정 패턴으로 사용하는 표현식을 의미합니다. Java, Python, Ruby, JavaScript 등 대부분의 프로그래밍 언어에서 정규 표현식을 라이브러리로 제공하고 있습니다.
정규 표현식 사용법
정규 표현식을 사용하기 위해선 사용되는 패턴에 대해서 알고 있어야 하는데요. 자주 사용되는 부분을 간략하게 정리해두었어요. 상세한 내용은 예전에 포스팅한 정규표현식 링크를 확인해 주세요!
https://sasca37.tistory.com/99
- ^ : 문자열 시작부터
- $ : 문자열 종료까지
- . : 줄 바꿈을 제외한 임의의 한 문자
- *: 바로 앞에 문자가 없거나 하나 이상 있을 때
- +: 바로 앞에 문자가 하나 이상 있을 때
- [^] : ^ 이후의 괄호 안 형식을 제외한 문자
- [] : [] 안의 형식을 일치하는 문자열
- {} : {} 앞의 문자열의 반복 개수 - ab{2,} : 2개 이상, ab{1,2} : 1부터 2까지
- ( ) : () 안의 내용을 하나의 묶음으로 처리
- | : OR 연산
- [0-9] : 0~9 숫자
- [a-z A-Z] : 모든 알파벳
- [ㄱ-ㅎ|ㅏ-ㅣ|가-힣] : 모든 한글
- \s : 모든 공백 문자
- \S : 공백 문자 제외
- \d : 0
9, \D : 09 제외 - \w : 모든 알파벳
- \S : 모든 알파벳 제외
String[] str2 = {"ASDF12" , "123456", "QWERTY", "as45aa", "567jkl"};
String regex = "^[0-9A-Z]{6}$"; // 문자열 시작부터 종료까지 (숫자거나 알파벳 대문자)로 이루어진 6글자
for (String data : str2) {
System.out.printf("%s \t %b\n", data, data.matches(regex));
}
[출력]
ASDF12 true
123456 true
QWERTY true
as45aa false
567jkl false
- 정규표현식은 Pattern, Matcher 라이브러리를 사용하여 다음과 같이 사용할 수 있습니다. ^[0-9A-Z]{6}$ 는 문자열 시작부터 종료까지 숫자 거나 알파벳 대문자 형태로 6글자로 이루어져 있어야 한다는 의미입니다.
라이브러리 소개
특정 문자열 찾기, 전화번호, 이메일 등 특정 패턴에 의해 검증이 필요할 때 자주 사용되는데요. 외우기엔 복잡하고, 금방 잊어버리게 되더라고요 매번 찾기도 번거로운데 (실제로 어제도 찾고 있었음) 정규표현식을 쉽게 사용할 수 있는 라이브러리가 있어서 공유드립니다! (특정 문자열을 패턴으로 만들고 싶을 때 유리)
9년 전에 만들다니.. 대단하네요 (Java, JavaScript, PHP, Python, C#, Object-C, Ruby, Groovy, C++ 제공)
https://github.com/lanwen/java-verbal-expressions
사용법
URL 주소 정규표현식으로 가져오기 예제
RegexUtil util = new RegexUtil.Builder()
.startOfLine() // 문자열 첫 단어(이어질 다음 패턴 적용) (^ 역할)
.then("http") // then : 반드시 있어야하는 문자열 - (parameter) 역할
.maybe("s") // maybe : 있을 수도 있고 없을 수도 있고 - (parameter)? 역할
.then("://")
.maybe("www.")
.anythingButNot(" ") // 아무거나 가능하지만 파라미터에 오는 것은 불가 (공백은 불가 : [^ parameter]* 역할)
.endOfLine() // 문자열 마지막 단어(직전 패턴 적용) ($ 역할)
.build();
String testWord = "https://sasca37.tistory.com";
System.out.println(util.toString()); // ^(http)(s)?(\:\/\/)(www\.)?([^\ ]*)$
System.out.println(util.test(testWord)); // true
System.out.println(util.testExact(testWord)); // true
- URL 패턴의 정규표현식을 라이브러리를 사용하면 쉽게 가져올 수 있다.
- toString() : 실제 수행되는 패턴 출력
- test(pattern) : 일치하는 패턴이 일부라도 존재하면 true (Matcher 라이브러리 find() 동작)
- testExtract(pattern) : 전체가 일치해야 true 리턴 (Matcher 라이브러리 matches() 동작)
소스 코드
깃허브에서 제공하는 소스 코드 자료입니다.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexUtil {
private final Pattern pattern;
public static class Builder {
private StringBuilder prefixes = new StringBuilder();
private StringBuilder source = new StringBuilder();
private StringBuilder suffixes = new StringBuilder();
private Pattern pattern;
private int modifiers = Pattern.MULTILINE;
private String sanitize(final String pValue) {
return pValue.replaceAll("[\\W]", "\\\\$0");
}
public Builder add(String pValue) {
this.source.append(pValue);
return this;
}
public RegexUtil build() {
pattern = Pattern.compile(new StringBuilder(prefixes)
.append(source).append(suffixes).toString(), modifiers);
return new RegexUtil(this);
}
public Builder startOfLine(boolean pEnable) {
this.prefixes.append(pEnable ? "^" : "");
return this;
}
public Builder startOfLine() {
return startOfLine(true);
}
public Builder endOfLine(final boolean pEnable) {
this.suffixes.append(pEnable ? "$" : "");
return this;
}
public Builder endOfLine() {
return endOfLine(true);
}
public Builder then(String pValue) {
this.add("(" + sanitize(pValue) + ")");
return this;
}
public Builder find(String value) {
this.then(value);
return this;
}
public Builder maybe(final String pValue) {
this.add("(" + sanitize(pValue) + ")?");
return this;
}
public Builder anything() {
this.add("(.*)");
return this;
}
public Builder anythingButNot(final String pValue) {
this.add("([^" + sanitize(pValue) + "]*)");
return this;
}
public Builder something() {
this.add("(.+)");
return this;
}
public Builder somethingButNot(final String pValue) {
this.add("([^" + sanitize(pValue) + "]+)");
return this;
}
public Builder lineBreak() {
this.add("(\\n|(\\r\\n))");
return this;
}
public Builder br() {
this.lineBreak();
return this;
}
public Builder tab() {
this.add("\\t");
return this;
}
public Builder word() {
this.add("\\w+");
return this;
}
public Builder anyOf(final String pValue) {
this.add("[" + sanitize(pValue) + "]");
return this;
}
public Builder any(final String value) {
this.anyOf(value);
return this;
}
public Builder range(String... pArgs) {
String value = "[";
for (int _to = 1; _to < pArgs.length; _to += 2) {
String from = sanitize((String)pArgs[_to - 1]);
String to = sanitize((String)pArgs[_to]);
value += from + "-" + to;
}
value += "]";
this.add(value);
return this;
}
public Builder addModifier(final char pModifier) {
switch (pModifier) {
case 'd':
modifiers |= Pattern.UNIX_LINES;
break;
case 'i':
modifiers |= Pattern.CASE_INSENSITIVE;
break;
case 'x':
modifiers |= Pattern.COMMENTS;
break;
case 'm':
modifiers |= Pattern.MULTILINE;
break;
case 's':
modifiers |= Pattern.DOTALL;
break;
case 'u':
modifiers |= Pattern.UNICODE_CASE;
break;
case 'U':
modifiers |= Pattern.UNICODE_CHARACTER_CLASS;
break;
default:
break;
}
return this;
}
public Builder removeModifier(final char pModifier) {
switch (pModifier) {
case 'd':
modifiers ^= Pattern.UNIX_LINES;
break;
case 'i':
modifiers ^= Pattern.CASE_INSENSITIVE;
break;
case 'x':
modifiers ^= Pattern.COMMENTS;
break;
case 'm':
modifiers ^= Pattern.MULTILINE;
break;
case 's':
modifiers ^= Pattern.DOTALL;
break;
case 'u':
modifiers ^= Pattern.UNICODE_CASE;
break;
case 'U':
modifiers ^= Pattern.UNICODE_CHARACTER_CLASS;
break;
default:
break;
}
return this;
}
public Builder withAnyCase(boolean pEnable) {
if (pEnable) {
this.addModifier('i');
} else {
this.removeModifier('i');
}
return this;
}
public Builder withAnyCase() {
return withAnyCase(true);
}
public Builder searchOneLine(boolean pEnable) {
if (pEnable) {
this.removeModifier('m');
} else {
this.addModifier('m');
}
return this;
}
public Builder multiple(final String pValue) {
String value = this.sanitize(pValue);
switch (value.charAt(0)) {
case '*':
case '+':
break;
default:
value += '+';
}
this.add(value);
return this;
}
public Builder or(final String pValue) {
if (this.prefixes.indexOf("(") == -1) {
this.prefixes.append("(");
}
if (this.suffixes.indexOf(")") == -1) {
this.suffixes.append(")" + this.suffixes.toString());
}
this.add(")|(");
if (pValue != null) {
this.then(pValue);
}
return this;
}
}
public boolean testExact(final String pToTest) {
boolean ret = false;
if (pToTest != null) {
ret = pattern.matcher(pToTest).matches();
}
return ret;
}
public boolean test(final String pToTest) {
boolean ret = false;
if (pToTest != null) {
ret = pattern.matcher(pToTest).find();
}
return ret;
}
private RegexUtil(final Builder pBuilder) {
pattern = pBuilder.pattern;
}
public String getText(String toTest) {
Matcher m = pattern.matcher(toTest);
StringBuilder result = new StringBuilder();
while (m.find()){
result.append(m.group());
}
return result.toString();
}
@Override
public String toString() {
return pattern.pattern();
}
}
- 전체 코드는 다음과 같이 구성되어 있습니다. 내부적으로 Builder를 구현해서 처리가 되어있는데, 안에 숫자 형식이나 길이에 대한 처리 기능을 추가하면 더 유연하게 사용할 수 있을 것 같네요
반응형