정규표현식

정규표현식이란?

정규 표현식은 패턴(pattern)으로 특정 목적을 위해 필요한 문자열 집합을 지정하기 위해 쓰이는 식이다.

메타문자

정규표현식에서 일정한 의미를 가지고 쓰는 특수문자를 메타 문자라고 부른다. 여기에 쓰이는 글자가 포함된 패턴을 넣으려면 해당 글자 앞에 \를 넣어줘야 한다.

  • ^ : 문자열의 시작
  • $ : 문자열의 종료. 옵션에 따라 문장의 끝 또는 문서의 끝에 매치된다.
  • . : 임의의 한 문자
  • []: 문자 클래스. 문자 클래스 안에 들어가 있는 문자는 그 바깥에서 하나의 문자로 취급된다.
    • ^ : 문자 클래스 내에서 ^는 not
    • - : ex) a-z는 a에서 z까지의 문자
  • | : or를 나타냄
  • ? : 앞 문자가 없거나 하나 있음
  • + : 앞 문자가 하나 이상임
  • * : 앞 문자가 0개 이상임
  • {n,m} : 앞 문자가 n개 이상 m개 이하. {0,1} 은 ?와 같은 의미다.
  • {n,} : 앞 문자가 n개 이상. 위의 형태에서 m이 생략된 형태이다. {0,} 이면 *와 같고 {1,} 이면 +와 같은 의미이다.
  • {n} : 앞 문자가 정확히 n개. {n,n} 과 같은 의미이다.
  • () : 하나의 패턴구분자 안에 서브 패턴을 지정해서 사용할 경우 괄호로 묶어주는 방식을 사용한다.
  • \s : 공백문자
  • \b : 문자와 공백 사이를 의미한다.
  • \d : 숫자 [0-9]와 같다.
  • \t : 탭문자
  • \w : 단어 영문자+숫자+_(밑줄) [0-9a-zA-Z_]
    문자 이스케이프는 대문자로 적으면 반대를 의미한다.

패턴 변경자

패턴구분자가 끝나면 그 뒤에 쓰는 것으로, 패턴에 일괄적으로 변경을 가할 때 사용한다. 정규식 엔진에 따라 변경자의 적용 방식이 상이하다.

  • i : 패턴을 대소문자 구분 없이 검사한다. 이 변경자를 사용할 경우 [a-z]로만 검사해도 자동으로 [a-zA-Z]와 같은 기능을 하게 된다. 영어가 아닌 언어(독일어, 프랑스어 등)를 다룰 때에는 버그 가능성이 있으므로 쓰지 않는 게 좋다. 대소문자라는 개념이 없는 한글, 한자, 가나문자는 이 패턴 변경자가 아무 역할도 하지 않는다.
  • s : 임의의 한 문자를 가리키는 . 메타 문자에 개행 문자(\n)도 포함시키도록 한다. 이 변경자를 사용하면 .이 줄바꿈도 임의의 한 문자로 취급하여 찾는다.
  • g : ^문자가 문장이 아닌 문서의 처음에, $ 문자가 문장의 끝(라인 피드 \n)이 아닌 주어진 문자열의 끝에 매치되게 변경한다.
  • m : 주어진 문자열에 줄바꿈이 있을 경우, 여러 줄로 취급하여 검사한다. (줄바꿈이 없다면 써도 의미가 없다.) 원래 정규표현식을 쓸 때 줄바꿈은 무시되는데, 이걸 사용하면 줄바꿈을 적용해서 검사한다. 그리고 ^은 한 줄의 시작, $는 한 줄의 끝으로 의미가 달라진다.
  • x : 공백 문자를 무시한다. 단, 이스케이프(역슬래쉬하고 같이 쓸 경우)하거나 문자 클래스 안에 있을 경우에는 예외. 정규식을 조금 더 읽기 편하게 만들어준다. 그러나 이 변경자를 지원하지 않는 엔진이 많은 게 단점이다.

Java

  • Java 경우에는 Pattern, Matcher 객체를 이용해서 원하는 문자열을 탐색할 수 있다.
  • String 객체의 replace도 정규식을 지원하는데 내부적으로는 Pattern, Matcher를 이용한다.
  • 특이하게도, Java에서는 Global 플래그가 디폴트로 적용되어 있다.
Pattern pattern = Pattern.compile("tomato", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher("tomato apple TOMATO");
while(matcher.find()) {
  System.out.println("count : " + matcher.groupCount());
  System.out.println("matched string : " + matcher.group());		// 패턴에 매칭된 문자열
  System.out.println("matched string : " + matcher.group(0));		// 패턴에 매칭된 문자열(matcher.group()과 동일)

}

- 결과 -
count : 0
matched string : tomato
matched string : tomato
count : 0
matched string : TOMATO
matched string : TOMATO

Javascript

  • Javascript 경우에는 RegExp와 String 객체에서 지원하는 함수를 이용해서 여러 정규식 처리를 할 수 있다.
  • RegExp 객체
    – exec() : 정규식 패턴과 일치하는 문자열을 배열로 반환한다. 없는 경우에는 null을 반환한다. 글로벌 플래그 사용시 lazy 하게 매칭된 문자열에 접근
    • test() : 정규식 패턴과 대응하는 문자열의 존재 여부를 true/false 로 반환한다.
    • match() : exec() 와 동일한 기능이지만, exec() 는 글로벌 플래그 사용시 즉시 매칭된 문자열 배열을 반환한다.
  • String 객체
    – search() : 정규식 패턴과 대응하는 문자열의 인덱스를 반환한다. 없는 경우에는 -1을 반환한다.
    • replace() : 정규식 패턴과 대응하는 문자열을 다른 문자열로 치환한다.
      – split() : 정규식 패턴을 기준으로 전체 문자열을 나눈다.
## exec() ##
let match;
const reg = /tomato/gi;
while((match = reg.exec('tomato apple TOMATO')) !== null) {
        // 매칭된 문자열 처리
}

- 결과 -
[ 'tomato',
  index: 0,
  input: 'tomato apple TOMATO',
  groups: undefined ]
[ 'TOMATO',
  index: 13,
  input: 'tomato apple TOMATO',
  groups: undefined ]

## test() ##
/tomato/gi.test('tomato apple TOMATO');

- 결과 -
true

## match() ##
"tomato apple TOMATO".match(/tomato/gi)

- 결과 -
[ 'tomato', 'TOMATO' ]

## replace() ##
"tomato apple TOMATO".replace(/tomato/gi, "banana")

- 결과 -
banana apple banana

## split() ##
"tomato apple TOMATO".split(/\s/)

- 결과 -
[ 'tomato', 'apple', 'TOMATO' ]

자주 쓰이는 패턴

1) 숫자만 : ^[0-9]*$

2) 영문자만 : ^[a-zA-Z]*$

3) 한글만 : ^[가-힣]*$

4) 영어 & 숫자만 : ^[a-zA-Z0-9]*$

5) E-Mail : ^[a-zA-Z0-9]+@[a-zA-Z0-9]+$

6) 휴대폰 : ^01(?:0|1|[6-9]) – (?:\d{3}|\d{4}) – \d{4}$

7) 일반전화 : ^\d{2,3} – \d{3,4} – \d{4}$

8) 주민등록번호 : \d{6} \- [1-4]\d{6}

9) IP 주소 : ([0-9]{1,3}) \. ([0-9]{1,3}) \. ([0-9]{1,3}) \. ([0-9]{1,3})

안녕하세요. 끄적이기를 좋아하는 개발자 이예빈입니다. 매일 일기를 쓰는 것 처럼 블로그를 쓰고 싶어요.
Leave a Reply

Your email address will not be published. Required fields are marked *