정규표현식

1 개요[편집]

정규표현식(Regular Expression; RegEx)이란 특정 형태(pattern; 패턴)의 데이터를 일괄적으로 찾거나 변경, 치환하기 위해 사용하는 형식언어이다. 정규식이라고도 하며, 영어로는 RegEx 혹은 RegExp로 줄여서 말하기도 한다. 개별 데이터를 사람이 찾거나 변경하는 것은 상당한 시간을 소모하지만, 컴퓨터에 특정 규칙을 지정하여 일괄적으로 찾거나 변경하는 것은 상대적으로 적은 시간을 소모한다. 일반적으로는 텍스트 문자열(문자와 숫자)을 다루는데 특화되어 있으나, 바이너리 데이터를 변경하는 데에도 많이 사용한다. 초창기에는 1970년대 UNIX에서 grep 필터나 텍스트 에디터에서 주로 사용되었는데, UNIX의 개발언어가 C(프로그래밍 언어)였고 C가 범용적으로 사용되어 후대 프로그래밍 언어에 영향을 준 까닭에, 대부분의 프로그래밍 언어가 정규표현식을 지원한다. 현재 POSIX 표준의 정규표현식 문법과 이를 확장한 Perl의 정규표현식 문법이 주류를 이루고, 각 프로그래밍 언어와 데이터베이스, 텍스트 에디터마다 다소 차이가 있는 정규표현식 문법을 지원한다.

컴퓨터 분야에서 정규표현식이 쓰이지 않는 경우는 극히 드물다. 예를 들어 웹 브라우저는 텍스트 형태로 표현된 HTML 문서를 시각화하기 위하여 태그를 패턴으로 읽어 처리한다. 리브레위키의 미디어위키 엔진은 위키문법에 맞춰 작성한 문서를 HTML 형식에 맞게 변형하여 웹브라우저에 전달한다. 리브레위키의 띄어쓰기, 맞춤법 들은 문서를 읽어 띄어쓰기가 안된 부분이나 흔한 맞춤법 실수를 올바르게 변경하도록 작동하고 있다. 특히 빅데이터 시대에 와서는 특정 형태의 데이터를 추출하고 사용가능하게 변형하는 것이 중요하게 되어, 정규표현식을 통계분야에서도 많이 활용하게 되었다.

2 구성요소[편집]

정규표현식의 구성요소는 일반 문자열과 형태를 지정하는 특수문자, 그리고 이를 구조화하는 대괄호, 중괄호, 소괄호로 이루어져 있다. 각 프로그래밍 언어와 텍스트 에디터마다 정규표현식의 문법이 미세하게 다르기 때문에, 여기서는 POSIX를 기준으로 설명한다.

2.1 문자열[편집]

정규표현식에서는 특수문자, 대괄호, 중괄호, 소괄호 등을 제외한 나머지를 문자열로 인식한다. 즉 특수문자를 제외한 영어와 한글, 한자 등의 모든 문자와 숫자이다. 단, 영어 등 서구권 언어의 경우에는 대문자와 소문자를 구별한다. 그러나 텍스트 에디터에 따라서는 대소문자 구별 기능을 끌 수도 있다.

원래 정규표현식은 한글, 한자 등의 인코딩이 없던 1970년대에 만들어졌기 때문에 특정 프로그래밍 언어나 텍스트 에디터에서는 인식이 안되거나, 입력한 글자와 실제 문서의 인코딩이 달라 정규표현식이 오작동하는 경우가 있었다. 특히 EUC-KR 인코딩과 유니코드간의 호환이 안되면 정규표현식이 작동하지 않았다. 한자의 경우에는 이 문제 외에도 유니코드에서의 한중일 통합한자 문제가 있다.

2.2 특수문자[편집]

특수문자에는 기호로 이루어진 메타 문자(MetaCharacter)와 이스케이프 문자로 나누어진다. 메타 문자는 정규표현식에서 특수한 기능을 수행한다. 본래 대괄호, 중괄호, 소괄호 및 수량자도 메타 문자에 속하지만 이들은 별도 항목으로 분리하였다. 아래의 표는 기본적인 정규표현식의 메타문자이다. 단, 정규표현식을 지원하는 프로그래밍 언어와 텍스트 에디터마다 약간의 차이가 있다.

메타문자의 기능 설명
메타문자 기능
. 숫자와 문자 특수기호, 공백 등을 포괄한 모든 범위의 한 글자
^ 문자열의 시작점. 그러나 일반적으로는 한 줄의 시작점을 의미한다. 문자클래스 집합에서는 다른 의미를 갖는다.
$ 문자열의 끝점. 그러나 일반적으로는 한 줄의 끝점을 의미한다.
\ 메타문자를 검색하기 위하여 특수문자 앞에 사용한다. 마침표 . 를 찾기 위해 \. 을 사용한다.
| '또는'을 의미한다. 고구려|백제|신라 를 찾으면 고구려 또는 백제, 신라를 찾게 된다.
\숫자 하위 표현식을 역참조하기 위하여 사용한다. 문법에 따라 \ 대신 $이 올 수 있다.

이스케이프 문자는 메타 문자 중 백슬래시(Backslash; 역슬래시. \ ; 한국어 입력 환경에서는 \로 표시되고 호환된다.[1])[2]와 영어소문자의 결합형태로 표현되며 대부분 공백, 줄바꿈, 문자, 숫자, 백스페이스 등의 문자클래스를 의미한다.

  • 이스케이프 문자 중 ASCII에서 규정한 것과 유니코드에서 쓰임새가 약간 달라진 것은 다음과 같다.
ASCII 규약과 유니코드 규약에서 약간 달라진 이스케이프 문자
항목 ASCII UNICODE
\w 영문자와 숫자, 언더스코어(_) 유니코드로 된 대부분의 언어와 숫자, 언더스코어(_)
\W 영문자와 숫자, 언더스코어(_)가 아닌 문자 유니코드로 된 대부분의 언어와 숫자, 언더스코어(_)가 아닌 문자
\d 10진수로 된 숫자 유니코드로 된 10진수 숫자
\D 10진수 숫자 가 아닌 모든 문자(공백 포함) 유니코드 10진수 숫자 가 아닌 모든 문자(공백 포함)
\s 탭, 줄바꿈 등 지정된 공백문자[\t\n\r\f\v] ASCII를 포함한, 유니코드에 규정된 전 세계의 모든 공백문자
\S 위 공백문자가 아닌 모든 글자 위 공백문자가 아닌 모든 글자
  • 이스케이프 문자 중 공백문자는 1970년대 컴퓨터와 같이 사용하던 라인 프린터(타자기와의 유사한 프린터로 도트매트릭스 프린터처럼 좌에서 우로 출력한 후 한 줄씩 내려간다.)로 인해 나타난 것이다. 당시에는 워드프로세서 프로그램이 없었기 때문에, 사용자들은 타자기 또는 컴퓨터의 일반적인 텍스트 파일에서 서식문서를 작성해야 하는 고충이 있었다. 이 때문에 사용자의 입력편의와 프린터를 제어하기 위한 문자가 고안되었다. 지금은 워드프로세서의 발달로 인하여 일반적인 텍스트 파일을 그대로 출력하는 일이 적어졌지만, 그 흔적이 지금도 유니코드 규약에 남아있는 것이다. 이 표에 나온 공백문자 중에서는 대부분 \t\n을 사용할 것이다.
공백문자 설명
\t 일반적으로 탭(TAB) 키를 입력했을 때 나오는 일정 간격을 유지하는 공백[3]이다. 수평 탭이라 한다.
\v 수직 탭(Vertical Tab)으로[4], Ctrl+K를 입력하면 넣을 수 있었다. 현재는 잘 쓰이지 않는다.
\f 페이지 넘김(Form Feed)[5]. Ctrl+L을 입력하면 넣을 수 있었다.
\r 캐리지 리턴(Carriage Return; CR). 원래는 Enter를 의미했다[6]. 과거 라인 프린터로 인해 탄생한 텍스트 파일의 줄바꿈 방식이다[7]. 대표적으로 과거 Mac OS 9까지는 사용자가 텍스트 편집에서 Enter를 입력하면 내부적으로 \r이 쓰였다.
현재 \r 만을 줄바꿈 방식으로 사용하는 운영체제는 없다. MS사의 도스와 윈도우는 줄바꿈에 \r 다음에 \n을 같이 사용한다.
\n 줄 바꿈(Newline; Line Feed; LF). 역시 라인 프린터로 인해 탄생한 텍스트 파일의 줄바꿈 방식이다.[8], UNIX, LINUX, Mac OS X 등은 사용자가 텍스트 편집에서 Enter를 입력하면, 내부적으로 \n을 쓴다.
물론 MS사의 도스와 윈도우는 줄바꿈에 \r 다음에 \n을 같이 사용한다.
    • 줄바꿈 방식을 부연설명하면, 유닉스계열 운영체제의 방식을 LF이라 하고, 매킨토시에서 사용하던 방식을 CR이라 하며, MS사가 사용하는 방식을 CR+LF 라고 한다. 그런데 유니코드를 사용하는 대부분의 최신 텍스트 에디터들은 운영체제별 줄바꿈의 차이를 자동으로 인식하여 읽고, \n을 쓰는 것으로도 줄 바꿈으로 인식하고 줄바꿈 방식을 지정하여 저장할 수 있으므로, \r, \r\n과 호환이 된다.

2.3 대괄호: 문자 클래스의 집합[편집]

문자 클래스란 문자열, 특수문자 등을 등장할 수 있는 형태를 표시한 것이다. 그 집합은 대괄호로 표시하며, 중간에 - 는 범위를 의미한다. 대괄호 내에서 이스케이프 문자 다음에 -가 오면 문자 -도 집합에 포함된다는 뜻이다.

  • [0-9]는 0부터 9까지의 숫자 집합을 의미하며, [1358]은 숫자 1, 3, 5, 8만의 숫자집합을 의미한다.
  • [A-Z]는 영어 대문자 집합을 의미하며, [AEIOUaeiou]는 영어에서 a, e, i, o, u로 이루어진 대소문자 집합을 의미한다.
  • [가-힣]은 가부터 힣까지의, 한글자모부분을 제외한 한글 집합을 의미한다.

한편 대괄호 내에 ^가 들어가면 ^ 뒤에 나오는 문자 클래스는 해당 집합에서 제외한다는 의미이다. 대괄호 내에서도 가장 앞에 있어야 한다. 만약 대괄호의 가장 앞에 ^가 존재하지 않거나, 이스케이프 문자 다음에 ^가 온다면 문자 ^를 찾으라는 의미가 된다.

  • [^0-9]는 0부터 9까지의 숫자 집합을 제외한다는 의미이며, 이스케이프 문자 \D와 동일한 의미이다.
  • ^[^A-Z]는 행의 앞쪽이 영어 대문자 집합인 것을 제외하고 찾으라는 의미이다.
  • [0-9+\-*/\^\(\)=]는 숫자와 사칙연산 부호 등(+, -, *, /, ^, =)을 찾으라는 의미이다. -와 소괄호 부분에는 문자로 인식하기 위하여 반드시 이스케이프 문자를 사용해야 한다. ^는 대괄호의 가장 앞에 쓰이지 않은 이상, 이스케이스 문자를 사용하지 않아도 무방하다.

POSIX 문법에서는 [: :]의 형태로 된 것이 있는데, 이스케이프 문자와 동일한 기능을 수행한다. 예를 들어 [:alnum:]은 언어로 된 모든 문자와 숫자를 찾는데, 언더스코어(_)를 찾지 않는다는 점을 제외하면 이스케이프 문자 \w와 기능이 동일하다.

2.4 중괄호: 수량자[편집]

수량자란 수량자 앞의 글자 혹은 문자클래스 집합의 글자수가 얼마나 되는지를 지정하는 것이다. 수량자는 중괄호로 표시하며, 중간에 , 를 통하여 최소수량과 최대수량을 지정할 수 있다. 수량자를 의미하는 특수문자로 ?, +, * 가 있다.

  • [0-9]{5} 는 5자리의 숫자 집합을 의미한다.
  • [A-Za-z]{3,} 는 3글자 이상의 영어 단어 집합을 의미한다.
  • [A-Za-z0-9]{4,8} 는 4글자 이상 8글자 이하의 영어 대소문자와 숫자로 이루어진 집합을 의미한다.
특수문자 대응수량자 설명
? {0,1} 문자가 없거나 하나인 경우
* {0,} 문자가 없거나 하나 이상 존재하는 경우
+ {1,} 문자가 하나 이상 존재하는 경우

수량자를 지정하지 않은 집합은 기본적으로 그 수량을 1로 이해하게 된다.

최대수량이 정해지지 않은 수량자 뒤에 특수문자 ?를 사용하면 게으른 수량자(Lazy quantification)라고 하여, 정규표현식을 충족가능한 작은 여러 개의 덩어리 형태를 찾게 된다. 게으른 수량자 ? 가 없다면 그 수량자는 탐욕적(Greedy)이라 하여 가능한 한 큰 덩어리로 만들게 된다.

  • .+ 은 한 줄을 의미하지만, 게으른 수량자를 이용해 .+?로 찾으면 .와 동일한 결과를 가져온다.
  • .{3,}은 3글자 이상의 한 줄을 찾지만, 게으른 수량자를 이용해 .{3,}?로 찾으면 한 줄을 3글자 단위로 끊은 결과를 보여준다.

2.5 소괄호: 하위 표현식[편집]

하위 표현식(subexpression; 서브 표현식)이란 정규표현식 내에서 특정 부분을 그룹으로 묶어 지정하는 것을 의미한다. 소괄호로 표시하며, 중간에 | 를 사용하여 또는을 의미하게 한다. 하위 표현식이 사용되면 소괄호 내에 있는 형태는 괄호별로 숫자가 순서대로 부여된다. 하위 표현식을 마치 프로그래밍 언어의 변수처럼 \1, \2[9]순으로 참조하게 되는데, 이를 역참조(Backreference)라고 한다.

예제문단
충청남도를 충청남도라고 한다. 옳다.
충청북도를 충청남도라고 한다. 잘못되었다.
충청도를 충청남도라고 한다. 역시 잘못되었다.
  • 충청(남|북)?도 는 충청남도, 충청북도, 충청도를 표시한다.
  • (충청(남|북)?도)를 \1 는 위에서 찾은 단어들을 하위 표현식으로 묶어서 역참조에 활용한 것이다. 이 경우 첫째 줄부분만이 검색된다.

한편 소괄호가 (?(역참조번호)참|거짓)형태로 ?가 사용되었을 경우에는 조건문 형태로 쓰인 것으로 조건이 참인 경우와 거짓인 경우를 나누어서 지정할 수 있다. 단, 여기에서 사용하는 역참조번호는 숫자만 들어가며, 이스케이프 문자는 사용하지 않는다.

예제문단
000-0000-0000
(000)0000-0000
  • (\()?\d{3}(?(1)\)|-)\d{4}-\d{4} 로 찾으면 역참조에 의하여 ( 이 있는 부분은 )가, (이 없는 부분은 -로 대체되어 두 줄이 모두 검색된다.

2.6 소괄호: 탐색자[편집]

소괄호속에서 가장 앞에 물음표가 들어가면 역참조를 이용한 조건형식 이외에 위치 탐색도 할 수 있다. 이러한 기능을 수행하는 것을 탐색자라고 한다. 탐색자에는 전방탐색과 후방탐색으로 나누어지며, 다시 긍정형과 부정형으로 나눌 수 있다. 탐색자는 메타문자 ^$처럼 범위를 한정하고 위치만을 지정하고 선택을 하지는 않는다는 공통점이 있다. 그러나 이러한 탐색자들은 메타문자 ^, $와 달리 소괄호 없이 단독으로 쓰일 수 없다.

탐색자 설명
?= 전방 탐색자(긍정형)
?<= 후방 탐색자(긍정형)
?! 전방 탐색자(부정형)
?<! 후방 탐색자(부정형)
  • .+(?=:) 는 콜론 앞의 것을 선택한다는 뜻이다. (콜론은 선택범위에서 제외된다.) 웹브라우저에서 현재 주소를 사용한다면 프로토콜 부분인 http 혹은 https 가 선택될 것이다.
  • (?<=//).*(?=/)/// 사이에 무엇인가 존재한다면 그 부분을 선택한다는 의미이다. 웹브라우저에서 현재 주소를 사용한다면 librewiki.net 이 선택될 것이다.

3 사용예시[편집]

미디어위키 엔진은 위키문법을 HTML 태그 문법으로 변환한다. 예를 들어 ==제목==을 <h2>제목</h2>으로, ===소제목===을 <h3>소제목</h3>으로 변환한다. 이를 정규표현식으로 나타내면 다음과 같다.[10]

찾기: (={3})(.+)(={3})

바꾸기: <h3>\2</h3>
찾기: (={2})(.+)(={2})
바꾸기: <h2>\2</h2>

웹사이트의 회원가입절차에서 이메일 주소 폼에 이메일을 제대로 입력했는지 검증하는데에도 활용된다.

^[0-9a-zA-Z]([\-.\w]*[0-9a-zA-Z\-_+])*@([0-9a-zA-Z][\-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9}$

영미식 날짜 표기(mm/dd/yyyy)를 연월일(yyyy-mm-dd) 순으로 변경하기 위해서는 다음 식을 사용한다.

  • 찾기: (\d{2})\/(\d{2})\/(\d{4})
    바꾸기: \3-\1-\2
  • 정규표현식을 작성하는 데에 한 가지 방법만 존재하지는 않는다. 다양한 방식이 동원될 수 있다.

찾기: (0[0-9]|1[012])\/([012][0-9]|3[01])\/(\d{4})
바꾸기: \3-\1-\2

프로그래밍 언어에서는 정규표현식에 다양한 함수를 사용하여 기능을 확장한다. 특히 Perl에서는 기존 정규표현식과 비교하여 더 많은, 놀라운 확장 기능을 제공하고 있다. 이 놀라운 Perl의 정규표현식 레퍼런스 페이지를 번역하고 싶으나, Perl은 라이센스에 BY-NC-ND, 즉 비영리-변경금지를 명시하고 있으므로 아래의 원문 링크를 참조하라.

4 관련항목[편집]

5 각주

  1. 엄밀한 의미에서는 백슬래시 \와 원화 기호 \는 유니코드에서 다르게 할당받아 전혀 다른 문자이다. 그러나 유니코드를 제정하기 전 국가표준에서 교체했다. KS X 1001역슬래시 참고
  2. 1970년대부터 2000년대 초반까지의 UNIXMS-DOS 등의 DOS환경에서는 ESC 키를 누르면 백슬래쉬가 입력되며 한 줄 내려가기 때문에 이스케이프 문자라고 한다.
  3. 당시에는 일반적인 텍스트 파일로는 표를 그릴 수 없었기 때문에 탭을 이용하여 표처럼 출력하게 하였다. Excel에서 텍스트를 나눌 때 구분기호로 탭을 사용하는 것도 이때문이다.
  4. 라인 프린터에서 문단간격을 위해 사용했었다
  5. 라인 프린터에 해당 페이지를 더 이상 입력하지 않는다는 것으로 일종의 쪽나누기 기능이었다.
  6. 1970-80년대만 해도 키보드에서 Enter의 명칭은 Return이었다.
  7. 라인 프린터의 카트리지가 원위치로 돌아간다는 의미였다.
  8. 라인 프린터에서 종이를 한 줄 내린다는 뜻이다.
  9. Perl 스타일은 $1, $2 순으로 가며, 각 프로그래밍 언어별로 역참조는 다르게 표현된다.
  10. 미디어위키 엔진은 PHP로 쓰여졌고 PHP의 다양한 함수(개수세기 등)와 변수를 이용해 실제 코드는 아래보다 짧을 것이다.