정규 표현식

정규 표현식(正規表現式, 영어: regular expression, 간단히 regexp 또는 regex, rational expression) 또는 정규식(正規式)은 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하는 형식 언어이다. 정규 표현식은 많은 텍스트 편집기와 프로그래밍 언어에서 문자열의 검색과 치환을 위해 지원하고 있으며, 특히 펄과 Tcl은 언어 자체에 강력한 정규 표현식을 구현하고 있다.
컴퓨터 과학의 정규 언어로부터 유래하였으나 구현체에 따라서 정규 언어보다 더 넓은 언어를 표현할 수 있는 경우도 있으며, 심지어 정규 표현식 자체의 문법도 여러 가지 존재하고 있다. 현재 많은 프로그래밍 언어, 텍스트 처리 프로그램, 고급 텍스트 편집기 등이 정규 표현식 기능을 제공한다. 일부는 펄, 자바스크립트, 루비, Tcl처럼 문법에 내장되어 있는 반면 닷넷 언어, 자바, 파이썬, POSIX C, C++ (C++11 이후)에서는 표준 라이브러리를 통해 제공한다. 그 밖의 대부분의 언어들은 별도의 라이브러리를 통해 정규 표현식을 제공한다.
정규 표현식은 검색 엔진, 워드 프로세서와 문서 편집기의 찾아 바꾸기 대화상자, 또 sed, AWK와 같은 문자 처리 유틸리티, 어휘 분석에 사용된다.

패턴

정규 표현식이라는 문구는 일치하는 텍스트가 준수해야 하는 "패턴"을 표현하기 위해 특정한 표준의 텍스트 신택스를 의미하기 위해 사용된다. 정규 표현식의 각 문자(즉, 패턴을 기술하는 문자열 안의 각 문자)는 메타문자(특별한 의미로)로 이해되거나 정규 문자('문자 그대로', 즉 '리터럴'의 의미로)로 이해된다. 이를테면 정규식 a. a는 단지 'a'와 일치하는 리터럴 문자이며 .는 새 줄을 제외한 모든 문자와 일치시키는 메타 문자이다. 그러므로 이 정규식은 이를테면 'a', 'ax', 'a0'과 일치시킬 수 있다. 더불어, 메타문자와 리터럴 문자는 주어진 패턴의 텍스트를 식별하기 위해 사용할 수 있으며, 또 수많은 인스턴스를 처리하기 위해 사용할 수도 있다. 패턴 일치는 정확히 동일한 일치에서부터 매우 포괄적인 유사 일치(메타문자에 의해 제어)에 이르기까지 다양하다. 이를테면 .는 매우 포괄적인 패턴이며, [a-z]('a'부터 'z'까지의 모든 문자 일치)는 덜 포괄적이며 a는 정확한 패턴(단지 'a'만 일치)이다. 메타문자 문법은 다양한 입력 데이터의 텍스트 처리의 자동화를 지시하는 정확하고 유연한 방법을 통해 표준 ASCII 자판을 사용하여 입력하기 쉬운 형태로, 미리 기술된 대상을 표현하기 위해 설계되었다.
이러한 신택스를 가지는 매우 단순한 정규 표현식의 경우는 문서 편집기에서 2가지 방식으로 발음되는 동일한 단어를 위치시키는 것을 들 수 있으며, 이를테면 seriali[sz]e는 "serialise"와 "serialize"를 모두 일치시킨다. 와일드카드 또한 이를 성취할 수 있으나 와일드카드가 패턴화할 수 있는 것으로 국한된다. (메타문자가 더 적으며 더 단순한 언어 기반임)
와일드카드 문자를 사용하는 경우는 파일 목록에서 비슷한 이름을 글로브 처리하는 것인 반면, 정규 표현식은 일반적으로 텍스트 문자열과 패턴 일치가 되는 애플리케이션에 보통 사용된다. 이를테면 ^[ \t]+|[ \t]+$는 줄 끝이나 줄 맨앞에 여분의 공백을 일치시킨다. 어떠한 숫자라도 일치시키기 위해 쓰이는 진보한 정규 표현식은 [+-]?(\d+(\.\d+)?|\.\d+)([eE][+-]?\d+)?이다. 더 많은 예를 보려면 예 문단을 참고할 것.

역사

정규 표현식은 스티븐 클레이니가 정규 집합(regular set)이라는 자신의 수학적 개념을 이용하여 정규 언어를 기술한 1956년이 기원이다. 형식 언어와 관련된 오토마타 이론의 하위 분야이자 이론 전산학에서 발생하였다. 패턴 일치의 초기 구현체들에는 SNOBOL 언어가 있으며, 실제로 정규식을 사용한 것은 아니지만 대신 독자적인 패턴 일치 구성체를 이용하였다.
여러 형태의 정규 표현식들이 1970년대에 벨 연구소에서 유닉스 프로그램에 사용되었는데, 이를테면 Vi, lex, sed, awk, expr, Emacs를 포함한다. 그 뒤로 정규 표현식은 1992년 POSIX.2에 표준화된 초기 형태들을 이용하여 다양한 프로그램에 채택되었다.
1980년대에 더 복잡한 정규 표현식이 펄에 등장하였으며 이는 1986년 헨리 스펜서가 작성한 정규 표현식 라이브러리에서 기인하며 나중에 이 작성자는 Tcl을 위한 고급 정규 표현식의 구현체를 작성하기도 했다. 펄 6에서는 펄의 정규 표현식 통합을 개선함과 동시에 파싱 표현 문법(parsing expression grammer)의 정의를 허용하기 위해 범위와 기능을 증가시키려는 노력이 있었다.
1997년을 기점으로 필립 하젤은 펄의 정규 기능을 모방하려는 시도 속에 PCRE를 개발하였으며 PHP와 아파치 HTTP 서버를 포함한 여러 현대적인 도구들에 사용된다.
오늘날 정규 표현식은 프로그래밍 언어, 문자 처리 프로그램(특히 lexer), 고급 문서 편집기 등의 프로그램에서 널리 지원된다. 정규 표현식 지원은 자바와 파이썬을 포함한 여러 프로그래밍 언어의 표준 라이브러리의 일부가 되었으며, 펄과 ECMA스크립트에서는 기본 문법으로 통합되었다.

문법

정규 표현식의 패턴은 대상 문자열과 일치시킨다. 이 패턴은 일련의 원자로 구성된다. 하나의 원자는 정규 표현식 패턴 안의 하나의 점이며, 대상 문자열과 일치시키기 위해 존재한다. 가장 단순한 형태의 원자는 리터럴(literal)이지만 원자를 일치시키기 위해 패턴을 묶을 때에는 메타문자로서 ( )를 사용해야 한다. 메타문자는 원자 외에도 얼마나 많은 원자가 있는지를 가리키는 수량자(quantifier), 선택적인 대안을 가리키는 논리적 OR 문자, 그리고 원자의 존재를 부정하는 NOT 문자, 그리고 전에 일치된 원자를 참조할 수 있게 하는 역참조(backreference)를 만드는 것을 도와준다.

구분 문자

프로그래밍 언어에서 정규 표현식을 입력할 때, 통상적인 문자열 리터럴로 표현할 수 있으므로 일반적으로 인용 부호로 처리된다. 이는 이를테면 C, 자바, 파이썬에서도 동일한데, 정규표현식 re는 "re"로 입력된다. 그러나 구분 문자로 슬래시를 사용하는 경우도 있는데 정규 표현식 re에 대해서 /re/를 사용하는 식이다. 이는 ed라는 편집기에서 기원하며, /는 검색을 위한 편집기 명령어이고, /re/라는 식은 특정한 범위의 줄들을 지정하는데 사용할 수 있다. 비슷한 방식이 sed에서 사용되는데, 검색 후 치환은 s/re/replacement/를 사용하며 패턴은 /re1/,/re2/처럼 특정한 범위의 줄을 지정하여 쉼표(,)로 결합할 수 있다. 이러한 표기법은 특히 펄에서도 사용된다.

펄과 PCRE

표현력과 (상대적으로) 양호한 가독성으로 인해 자바, 자바스크립트, 파이썬, 루비, 마이크로소프트의 닷넷 프레임워크, XML 스키마 등의 여러 수많은 유틸리티들과 프로그래밍 언어들은 펄의 정규식과 비슷한 문법을 채택하고 있다. Boost와 PHP와 같은 일부 언어들과 도구들은 여러 방식의 정규식을 지원한다. 펄 파생 정규식 구현체들은 완전히 동일한 것은 아니며 일반적으로 1994년에 출시된 펄 5.0의 기능의 하위 집합을 구현하고 있다. 펄은 종종 다른 언어에서 발견되는 기능들을 도입하고 있는데, 이를테면 펄 5.10은 PCRE와 파이썬에서 개발되는 문법 확장들을 구현한다.

이용

정규 표현식은 다양한 텍스트 처리 작업, 더 일반적으로 문자열 처리에 유용하며, 여기에서 데이터는 반드시 텍스트일 필요는 없다. 일반적으로 데이터 검증, 데이터 스크래핑(일반적으로 웹 스크래핑), 데이터 랭글링, 단순 파싱, 문법 강조 시스템 개발 등의 작업에 응용된다.
정규 표현식이 인터넷 검색 엔진에 유용할 수 있으나 전체 데이터베이스를 거쳐 이것들을 처리하기에는 정규 표현식의 복잡도와 설계에 따라 컴퓨터 자원을 과도하게 소비할 수 있다. 대개의 경우 시스템 관리자들이 정규 표현식 기반 쿼리를 내부적으로 수행할 수 있지만 대부분의 검색 엔진들은 대중에게 정규 표현식 지원을 제공하지 않는다.