정규 표현식(Regular expression) 쉽게 이해하기
정규 표현식이란?
정규 표현식은 특정한 문자열의 규칙을 표현하는데 사용하는 형식언어이다.
(즉, 특정 규칙을 가지고 있는 문자열들; e.g. 1글자의 알파벳 소문자 = a,b,c,d,...)
보통 '문자열의 규칙'을 표현하기 위해서는 일반적인 조건문을 이용하면 복잡하게 표현해야하지만,
정규표현식을 이용하면 간결한 형태로 표현할 수 있다.
하지만, 규칙에 대하여 잘 숙지하지 않으면(규칙을 이해하고 있더라도 찬찬히 뜯어보기 전에는..)
알아보기 힘든 형태를 띄고 있는 것 또한 사실이다.
정규 표현식은 크게 문자와 메타문자로 구성된다.
아래에서 먼저 메타문자에 대하여 설명 한 뒤 메타문자와 문자를 이용하여 어떻게 정규표현식을 사용하는지 알아보도록 하자.
메타문자
메타문자는 문자를 표현하는 것 이외에 특정한 규칙을 표현하기 위한 문자들이다.
대부분의 경우 같은 메타문자들을 사용하지만 특정 종류에 따라 메타문자가 다른 경우도 있으므로
제대로 사용이 안될 경우 해당 정규식의 표현 방법을 찾아보아야 한다.
^x : 입력(줄) 시작 + x
x$ : x + 입력(줄) 끝
\Ax : 문자열의 시작(내부 줄바꿈 제외) + x
x\z : x + 문자열의 끝(내부 줄바꿈 제외)
. : 개행 문자를 제외한 임의의 문자 1개
x{n} : x가 n번 반복
x{n,} : x가 n번 이상 반복
x{n,m} : x가 n번 이상 m번 이하 반복
x? : 문자 x 또는 문자 없음(x{0,1})
x+ : x가 1번 이상 반복(x{1,})
x* : x 가 0번 이상 반복(x{0,})
--> +, *, {n,m}과 같이 여러 값을 가질 수 있는 규칙의 경우 기본적으로 greedy(좀 더 큰 결과값을 찾음)하게 동작하지만 ?기호를 붙이면 lazy(작은 결과를 찾음)하도록 동작한다.
x|y : x 또는 y
(x) : ()안의 내용을 캡쳐하여 그룹화 (레퍼런스 캡쳐 관련하여 Ref.2를 참조바람)
(x)(y) : ()안의 내용을 캡처하며 앞에서부터 그룹 번호를 부여함.
(?:y) : 캡쳐하지 않는 그룹을 생성
\n : (n은 1에서 9까지의 정수 [1-9])정규식 안 n번 괄호(그룹)의 최근 일치 부분(역참조)과 같음.
x(?=y) : y가 뒤 따라오는 x에만 일치
x(?!y) : y가 뒤 따라오지 않는 x에만 일치
[...] : Bracket expression이며 가능한 문자셋을 표시한다.(자세한 내용에 대해서는 후술)
정규 표현식에서 이스케이프 문자 '\' 뒤에 사용되는 문자를 특별하게 해석할 것을 요구하며,
특수한 문자(또는 문자집합)나 메타문자에서 먼저 사용하고 있는 글자(e.g. [](){}^$ 등)를 표시하기 위하여 사용한다.
\A : 문자열의 시작(내부 줄바꿈 제외)
\z : 문자열의 끝(내부 줄바꿈 제외)
\w : '_'를 포함한 알파벳 또는 숫자 [A-Za-z0-9_]
\W : 비 단어문자 [^A-Za-z0-9_]
\b : 길이가 0인 단어의 경계를 의미 즉, 매칭되는 결과물에는 경계가 포함되지 않는다(^\w | \w$ | \W\w | \w\W) (Ref.3)
\B : 단어의 경계가 아닌 것.
\d : 숫자 문자 [0-9]
\D : 숫자 문자가 아닌 것 [^0-9]
\xhh : hh(hex문자 2개)
\uhhhh : hhhh(hex문자 4개)
\f : 폼 피드(U+000C)
\n : 줄 바꿈(U+000A)
\r : 캐리지 리턴(U+000D)
\t : 탭(U+0009)
\v : 수직 탭(U+000B)
\s : 스페이스, 탭, 폼 피드, 줄 바꿈 문자를 포함한 하나의 공백문자 [ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]
\S : \s가 아닌 모든 문자
\0 : 널 문자(U+0000)
\c : 컨트롤 문자(e.g. \cM 은 control-M(U+000D)와 일치함)
[](Bracket expression)
[]을 통하여 문자셋을 표현할 때에 주의할 점은 대괄호 안에서는 메타문자를 사용할 수 없거나
일반 문자가 다른 형태로 사용되게 된다.
[a-z] : a부터 z까지의 문자
[^ab] : a와 b를 제외한 모든 문자(^는 '줄의 시작'으로 처리되지 않고 not으로 처리된다.)
[ac] : a | c
[a.c] : a | . | c ('.'이 임의의 문자로 처리되지 않고, 문자 '.'로 처리된다.)
[\b] : 백스페이스
[-] : '-' 문자의 경우 문자로 인식되기 위해서는 []안에 첫 번째 혹은 마지막으로 위치하여야 한다.
[]] : '[' 문자의 경우 문자로 인식되기 위해서는 []안에 첫 번째 혹은 ^문자 바로 다음에 위치하여야 한다.
캐릭터 클래스(POSIX Extended)
[...]를 이용하여 문자셋을 표현하는 것이 가능하지만, 직관적으로 이해하기 힘든 점이 있을 수 있다.
때문에 직관적으로 이해하기 쉬운 형태로 문자셋을 표현할 수 있도록 캐릭터 클래스를 제공하고 있으며 그 내용은 다음과 같다.
(표준이 아닌 부분이 있을 수 있음)
[:alnum:] : 알파벳 및 숫자 [A-Za-z0-9]
[:alpha:] : 알파벳 [A-Za-z]
[:blank:] : 공백과 탭[ \t]
[:cntrl:] : 컨트롤 문자 [\x00-\x1F\x7f]
플래그
플래그를 이용하여 정규식의 검색 방법을 설정할 수 있다.
g : 전체 검색
i : 대소문자 무시
m : 여러 줄 검색
y : 현재 위치부터 검색
예제
정규표현식을 이용하여 특정 규칙이 있는 여러 문자열들을 검색할 수 있다.
e.g. 핸드폰 번호 찾기
홍길동 : 010-1234-5678
에서 핸드폰 번호를 찾고 싶다면
\d{3}-\d{4}-\d{4} 과 같이 값을 찾을 수 있다.
만약 이 중에서 끝 4자리가 5천이 넘는 숫자를 찾고 싶다면
\d{3}-\d{4}-[5-9]\d{3} 와 같이 찾을 수 있다.
속칭 '황금번호'와 같은 패턴을 찾고 싶다고 한다면 그룹의 역참조를 이용하여 찾아야 한다.
( 괄호('()')를 이용하여 그룹을 캡쳐하고 캡처한 내용을 \1~\9를 이용하여 역참조 한 형태로 반복시킨다.)
010-AAAA-BBBB 와 같은 형태라면
/010-(\d)\1{3}-(\d)\2{3}/ 와 같이 찾을 수 있을 것이다.
e.g. 파일 이름 찾아보기
자주 컴퓨터에서 파일을 찾는 사람들의 경우 윈도우의 검색이 느리기 때문에 'Everything'이라는 프로그램을 종종 사용하는 경우가 있다.
이 프로그램에서는 정규표현식을 이용한 찾기를 지원하는데(사실 Ctrl+f로 호출할 수 있는 대부분의 찾기가 정규표현식을 제공한다.)
정규표현식을 사용하지 못하는 경우 파일을 찾는데 애를 먹는 경우가 있다.
예를 들어 c:\ 안에 있는 모든 hello.c 파일과 hello.h 파일을 찾고싶다면
c:\\.+\\hello\.[ch]$ 라고 찾을 수 있을 것이다.
찬찬히 뜯어보면
c:\\ : c:\를 뜻하며 \가 메타문자로 해석하길 요구하는 글자이기 때문에 \\로 사용한다.
.+ : 1개 이상의 문자를 뜻한다. 따로 요구하지 않는 경우 정규표현식 검색은 greed(더 큰 것을 찾는다)하게 동작하기 때문에 최대한 많은 길이를 찾는다.
hello\. : hello. 을 뜻함.
[ch]$ : c 또는 h를 의미하며 $가 붙었기 때문에 이 줄의 끝일 경우에만 매칭된다.
와 같이 해석 가능하다.
e.g. 특수한 문자열 찾기
정규표현식을 익히는 좋은 방법중의 하나는 아주 긴 문자열들을 다뤄보는 것이다.
Python challenge 의 문제에 이런 문제가 있었는데, (물론 기억에 의존하는 것이기 때문에 정확히 같은 문제는 아니다.)
" 3개 이상의 큰 알파벳 사이에 같힌 글자를 찾아라" 였다.
그리고 문자열을 보면 알파벳 뿐만 아니라 온갖 기호들이 섞여있다.
여기서 매칭되는 문자를 찾기 위해서는 조건문을 꽤나 복잡하게 만들어야 하는데
정규표현식을 이용하면 간단하게 찾아낼 수 있다.
[A-Z]{3,} : 3개 이상의 큰 알파벳
[a-z] : 작은 알파벳
[A-Z]{3,} : 3개 이상의 큰 알파벳
이렇게 찾고 ()괄호를 이용해서 작은 알파벳을 캡쳐하면
[A-Z]{3,}([a-z])[A-Z]{3,}
와 같이 정규표현식이 나오고 결과값은 그룹으로 지정되어 리스트형태로 도출된다.
이런 방식으로 다양하게 정규 표현식을 사용 가능하니
필요할 때 보고 편리하게 사용해 보도록 하자.
Reference :
[1] https://en.wikipedia.org/wiki/Regular_expression
[2] http://www.regular-expressions.info/refcapture.html
[3] http://www.regular-expressions.info/wordboundaries.html
[4] http://www.nextree.co.kr/p4327/