PCRE 정규표현식 문법과 패턴 매칭 활용
PCRE 정규표현식의 문법, 캡처와 룩어라운드, 재귀 패턴, 성능 최적화와 보안 활용 방식을 정리한다.
2026-08-14 · 최초 발행 2025-06-15
문자열 규칙을 표현하는 PCRE
PCRE는 Perl 프로그래밍 언어의 정규표현식 문법과 호환되도록 개발된 C 라이브러리다. 1997년 Philip Hazel이 개발했으며, 현재도 널리 사용되는 오픈 소스 프로젝트로 자리 잡고 있다.
정규표현식은 문자열의 패턴을 기술하는 형식 언어다. 검색, 추출, 치환 같은 작업에서 쓰이며, 현대적인 프로그래밍 언어와 도구 다수가 PCRE 문법을 채택하거나 지원한다.
PCRE는 Perl 5 문법과 거의 완벽하게 호환하고 유니코드를 다룰 수 있다. 중첩된 텍스트 구조를 위한 재귀 패턴, 조건에 따라 분기하는 서브패턴, 이름으로 결과를 참조하는 캡처 그룹도 제공한다.
패턴을 이루는 메타문자와 문자 클래스
기본 메타문자는 패턴의 범위와 반복, 분기를 정한다. .은 줄바꿈을 제외한 문자 하나를, ^와 $는 각각 문자열의 시작과 끝을 가리킨다. *, +, ?는 앞 요소의 반복을 표현하고, |는 대안 패턴을 나눈다. \는 메타문자를 이스케이프할 때 사용한다.
문자 클래스는 매칭할 문자 집합을 좁히는 방식이다. [abc]는 a, b, c 중 하나를, [^abc]는 이들을 제외한 문자 하나를 찾는다. [a-z]는 소문자 범위를 뜻하며, \w, \d, \s는 각각 단어 문자, 숫자 문자, 공백 문자를 나타낸다.
예제: 이메일 주소 검증
/^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,}$/
반복 범위와 캡처 결과 다루기
{n}은 정확히 n번, {n,}은 n번 이상, {n,m}은 n번 이상 m번 이하의 반복을 지정한다. 수량자는 기본적으로 가능한 긴 구간을 찾는 그리디 매칭을 수행한다. 뒤에 ?를 붙이면 가능한 짧은 구간을 택하는 논그리디 매칭이 된다.
예제: HTML 태그 추출
그리디: /<.+>/ <!-- <div>Hello</div>에서 "<div>Hello</div>" 전체 매칭 -->
논그리디: /<.+?>/ <!-- <div>Hello</div>에서 "<div>" 부분만 매칭 -->
그룹은 패턴 일부를 묶고 필요하면 결과를 캡처한다. (...)는 그룹화와 캡처를 함께 수행하며, (?:...)는 그룹화만 한다. (?<name>...) 또는 (?P<name>...)는 캡처 결과에 이름을 붙이는 문법이다.
예제: 날짜 형식 파싱
/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
룩어헤드와 룩비하인드는 특정 문자열 자체를 소비하지 않고, 현재 위치의 앞뒤 조건을 확인한다. (?=...)와 (?!...)는 뒤쪽 패턴의 존재 여부를 검사하고, (?<=...)와 (?<!...)는 앞쪽 패턴의 존재 여부를 검사한다.
예제: 비밀번호 검증
/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$/
<!-- 숫자, 소문자, 대문자를 포함하는 8자 이상의 문자열 -->
중첩 구조와 조건에 따른 분기
재귀 패턴은 중첩된 구조를 처리할 때 사용한다. (?R)은 전체 패턴을 재귀적으로 참조하고, (?n)은 n번째 캡처 그룹을 재귀적으로 참조한다.
예제: 괄호 균형 검사
/\((?:[^()]|(?R))*\)/
조건부 패턴은 조건의 참과 거짓에 따라 서로 다른 패턴을 매칭한다. (?(condition)yes-pattern|no-pattern) 형식을 사용한다.
예제: HTML 태그의 시작과 끝 태그 일치 확인
/<([a-z]+)(?:\s[^>]*)?>(.*?)<\/(?:(?(1)\1|[a-z]+))>/i
웹·텍스트·보안 처리에서의 사용
웹 개발에서는 이메일, 전화번호, URL 같은 사용자 입력 검증과 HTML 파싱 및 조작, URL 라우팅에 활용할 수 있다.
// PHP에서 이메일 주소 검증
if (preg_match('/^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,}$/', $email)) {
echo "유효한 이메일 주소입니다.";
}
로그 분석, 데이터 스크래핑, 텍스트 정규화처럼 필요한 값을 문자열에서 뽑아내는 작업도 대표적인 적용 영역이다.
# Python에서 로그 파일에서 IP 주소 추출
import re
log_line = '192.168.1.1 - - [10/Oct/2023:13:55:36 -0700] "GET /index.html HTTP/1.1" 200 2326'
ip_pattern = r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
ip = re.search(ip_pattern, log_line).group(1)
print(ip) # 출력: 192.168.1.1
보안 영역에서는 침입 탐지 시스템의 패턴 매칭, 악성 코드 시그니처 검출, 입력 검증을 통한 인젝션 공격 방어에 사용된다.
예제: SQL 인젝션 패턴 탐지
/(\b(select|insert|update|delete|drop|alter)\b.*\b(from|into|table)\b)/i
백트래킹 비용을 통제하는 패턴 설계
복잡한 패턴은 백트래킹 때문에 성능이 저하될 수 있다. 탐욕적 수량자를 무조건 사용하기보다 필요한 범위를 지정하고, ^, $ 앵커로 탐색 구간을 제한하는 편이 낫다.
캡처가 필요하지 않은 그룹은 비캡처 그룹 (?:)로 처리할 수 있다. 대안 구문에서는 공통 접두사나 접미사를 추출해 분기를 줄이는 방식도 유효하다. PCRE2는 정규표현식을 기계어로 컴파일하는 JIT 기능을 제공하며, 복잡한 패턴이나 대용량 데이터 처리에서 특히 유용하다.
다른 정규표현식 엔진과의 차이
| 엔진 | 특징 | 사용 환경 |
|---|---|---|
| PCRE | Perl 호환성, 강력한 기능, 높은 성능 | PHP, Apache, C/C++ 응용 프로그램 |
| RE2 | 선형 시간 보장, 백트래킹 없음 | Google 제품, Go 언어 |
| JavaScript RegExp | 웹 브라우저 내장, ECMAScript 표준 | 웹 브라우저, Node.js |
| .NET Regex | 풍부한 API, 정적 컴파일 | .NET 플랫폼 |
PCRE의 강점은 표현력과 고급 기능, 유니코드 기반의 다국어 처리, 그리고 PCRE2의 JIT 컴파일 지원이다. 반대로 복잡한 패턴은 성능 저하를 유발할 수 있고, 고급 문법은 이해하기 어렵다. 정규표현식 DoS(ReDoS) 가능성도 검토 대상이다.
검증과 추출에 사용할 수 있는 패턴
IP 주소를 확인할 때는 IPv4와 IPv6에 다음 패턴을 적용할 수 있다.
IPv4: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
IPv6: /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/
신용카드 번호 형식에는 다음 정규표현식을 사용할 수 있다.
/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12}|(?:2131|1800|35\d{3})\d{11})$/
HTML 태그를 대상으로 속성까지 포함해 매칭하려면 다음과 같은 패턴을 쓸 수 있다.
/<([a-z]+)(?:\s+([a-z]+)(?:\s*=\s*(?:"([^"]*)")|(?:'([^']*)')|([^>\s]+)))?(?:\s*(?:\/|\?))?>/i
PCRE2로 이어진 변화
PCRE2는 2015년에 출시된 PCRE의 주요 개정판이다. API가 재설계됐고 성능과 유니코드 지원, JIT 컴파일러가 개선됐다.
병렬 매칭 지원 확대, SIMD 명령어를 활용한 하드웨어 가속, 웹어셈블리(WebAssembly)를 통한 브라우저 내 고성능 정규표현식 처리, 백트래킹 제한 메커니즘을 통한 보안 강화도 최신 동향으로 언급된다. PCRE는 앞으로도 다양한 응용 분야에서 중요한 역할을 할 전망이다.