정규 표현식: 초보자를 위한 가이드
· 12분 읽기
목차
정규 표현식이란?
정규 표현식(Regular expressions)은 일반적으로 regex 또는 regexp로 줄여 부르며, 검색 패턴을 정의하는 문자 시퀀스입니다. 이 강력한 도구는 텍스트 데이터 내에서 문자열 매칭, 검증 및 조작에 광범위하게 사용됩니다. 정규 표현식을 마스터하면 텍스트 검증, 데이터 추출, 데이터 포맷팅과 같은 작업을 놀라운 효율성으로 자동화할 수 있습니다.
처음 보면 정규 표현식은 밀도 높고 암호 같은 구문 때문에 위협적으로 보일 수 있습니다. 하지만 핵심 구성 요소를 이해하면 수백 줄의 절차적 코드가 필요한 정교한 데이터 처리 기술의 문이 열립니다. 정규 표현식을 패턴 매칭을 위해 특별히 설계된 전문 미니 언어로 생각하세요.
소프트웨어 개발, 데이터 분석, 시스템 관리, 콘텐츠 관리, 웹 스크래핑 등 수많은 실제 시나리오에서 정규 표현식을 접하게 됩니다. 일반적인 사용 사례로는 로그 파싱, 폼 검증, CSV 파일의 데이터 변환, 검색 및 바꾸기 작업, 비구조화된 텍스트에서 구조화된 정보 추출 등이 있습니다.
프로 팁: 정규 표현식은 JavaScript, Python, Java, PHP, Ruby, Go를 포함한 거의 모든 최신 프로그래밍 언어에서 지원됩니다. VS Code, Sublime Text와 같은 텍스트 에디터와 grep, sed와 같은 명령줄 도구에도 내장되어 있습니다.
정규 표현식 구문 이해하기
정규 표현식의 구문은 강력한 패턴 매칭 기능을 만들기 위해 결합되는 기본 요소들로 구성됩니다. 표기법이 처음에는 암호처럼 보일 수 있지만, 각 기호는 어떤 텍스트가 패턴과 일치해야 하는지 정의하는 특정 목적을 가지고 있습니다.
모든 정규 표현식 패턴의 기초를 형성하는 필수 구성 요소를 분석해 보겠습니다. 이러한 핵심 요소를 이해하면 거의 모든 텍스트 매칭 시나리오에 대한 패턴을 구성할 수 있습니다.
기본 메타문자
메타문자는 정규 표현식에서 문자 그대로 매칭되는 것이 아니라 특정 의미를 가진 특수 문자입니다. 가장 기본적인 것들은 다음과 같습니다:
.(점): 줄바꿈을 제외한 모든 단일 문자와 일치합니다. 예를 들어,a.c는 "abc", "a2c", "a@c"와 일치하지만 "ac"와는 일치하지 않습니다.\(백슬래시): 특수 문자를 이스케이프하여 문자 그대로 일치시킵니다. 실제 마침표와 일치시키려면\.를 사용하세요.|(파이프): OR 연산자로 작동합니다. 패턴cat|dog는 "cat" 또는 "dog"와 일치합니다.
메타문자를 문자 그대로 일치시켜야 할 때(실제 별표나 마침표를 검색하는 경우), 백슬래시로 이스케이프해야 합니다. 예를 들어, \*는 리터럴 별표 문자와 일치합니다.
빠른 팁: 정규 표현식 매치 테스터를 사용하여 실시간으로 패턴을 실험하고 정규 표현식이 정확히 무엇과 일치하는지 확인하세요.
문자 클래스와 범위
문자 클래스를 사용하면 특정 집합의 문자 중 하나와 일치시킬 수 있습니다. 대괄호로 묶이며 단일 위치에서 여러 가능한 문자를 지정하는 간결한 방법을 제공합니다.
기본 문자 클래스
[abc]: 'a', 'b' 또는 'c'인 단일 문자와 일치합니다.[^abc]: 'a', 'b' 또는 'c'를 제외한 모든 문자와 일치합니다. 대괄호 안의 캐럿은 클래스를 부정합니다.[a-z]: 'a'부터 'z'까지의 모든 소문자와 일치합니다.[A-Z]: 모든 대문자와 일치합니다.[0-9]: 0부터 9까지의 모든 숫자와 일치합니다.[a-zA-Z0-9]: 모든 영숫자 문자와 일치합니다.
단일 문자 클래스 내에서 여러 범위를 결합할 수 있습니다. 예를 들어, [a-zA-Z0-9_]는 모든 문자, 숫자 또는 밑줄과 일치하며, 사용자 이름이나 변수 이름을 검증하는 데 일반적으로 사용됩니다.
미리 정의된 문자 클래스
대부분의 정규 표현식 엔진은 일반적인 패턴에 대한 단축 문자 클래스를 제공합니다:
| 단축 | 동등 | 설명 |
|---|---|---|
\d |
[0-9] |
모든 숫자 |
\D |
[^0-9] |
숫자가 아닌 모든 것 |
\w |
[a-zA-Z0-9_] |
모든 단어 문자 |
\W |
[^a-zA-Z0-9_] |
단어 문자가 아닌 모든 것 |
\s |
[ \t\n\r\f\v] |
모든 공백 문자 |
\S |
[^ \t\n\r\f\v] |
공백이 아닌 모든 문자 |
이러한 단축 클래스는 패턴을 더 읽기 쉽고 유지 관리하기 쉽게 만듭니다. 예를 들어, \d{3}-\d{3}-\d{4}는 전화번호를 일치시키는 데 [0-9]{3}-[0-9]{3}-[0-9]{4}보다 훨씬 명확합니다.
수량자 설명
수량자는 패턴에서 요소가 몇 번 나타나야 하는지 지정합니다. 수정하는 요소 뒤에 배치되며 가변 길이 패턴을 일치시키는 데 필수적입니다.
기본 수량자
*: 0회 이상 일치합니다. 패턴ab*c는 "ac", "abc", "abbc", "abbbc" 등과 일치합니다.+: 1회 이상 일치합니다. 패턴ab+c는 "abc", "abbc"와 일치하지만 "ac"와는 일치하지 않습니다.?: 0회 또는 1회 일치합니다(앞의 요소를 선택 사항으로 만듭니다). 패턴colou?r는 "color"와 "colour" 모두와 일치합니다.
특정 수량자
반복 횟수를 정확하게 제어하려면 중괄호를 사용하세요:
{n}: 정확히 n회 일치합니다.\d{4}는 정확히 4개의 숫자와 일치합니다.{n,}: n회 이상 일치합니다.\d{3,}는 3개 이상의 숫자와 일치합니다.{n,m}: n회에서 m회 사이로 일치합니다(포함).\d{2,4}는 2, 3 또는 4개의 숫자와 일치합니다.
탐욕적 vs. 게으른 수량자
기본적으로 수량자는 "탐욕적"입니다. 가능한 한 많은 텍스트와 일치합니다. 수량자 뒤에 물음표를 추가하면 "게으른" 또는 "비탐욕적"이 되어 가능한 한 적게 일치합니다.
문자열 "<div>content</div>"를 고려하세요:
<.+>(탐욕적)은 첫 번째<에서 마지막>까지 전체 문자열과 일치합니다<.+?>(게으른)은<div>만 일치시킨 다음</div>를 별도로 일치시킵니다
프로 팁: 게으른 수량자는 HTML, XML 또는 중첩된 구조를 파싱할 때 중요합니다. 구분 기호 사이에서 너무 많은 콘텐츠와 일치하는 것을 방지합니다.
앵커와 경계
앵커는 문자와 일치하지 않고 텍스트 내의 위치와 일치합니다. 문자열의 어디에서나가 아니라 특정 위치에서 패턴이 일치하도록 하는 데 필수적입니다.
위치 앵커
^: 줄 또는 문자열의 시작과 일치합니다.^Hello는 시작 부분에서만 "Hello"와 일치합니다.$: 줄 또는 문자열의 끝과 일치합니다.world$는 끝 부분에서만 "world"와 일치합니다.\A: 문자열의 절대 시작과 일치합니다(다중 줄 모드의 영향을 받지 않음).\Z: 문자열의 절대 끝과 일치합니다(다중 줄 모드의 영향을 받지 않음).
시작 및 끝 앵커를 결합하면 전체 문자열이 패턴과 일치하도록 보장합니다. 예를 들어, ^\d{5}$는 정확히 5개의 숫자만 포함하고 다른 것은 없는 문자열과 일치합니다. 미국 우편번호를 검증하는 데 완벽합니다.
단어 경계
단어 경계는 더 큰 단어의 일부를 실수로 일치시키지 않고 전체 단어를 일치시키는 데 매우 유용합니다:
\b: 단어 경계와 일치합니다(단어 문자와 비단어 문자 사이의 위치).\B: 비단어 경계와 일치합니다.
패턴 \bcat\b는 독립적인 단어로서의 "cat"과 일치하지만 "category"나 "concatenate"의 "cat"과는 일치하지 않습니다. 이는 특정 단어를 대상으로 하는 검색 및 바꾸기 작업에 필수적입니다.
그룹과 캡처
그룹을 사용하면 여러 문자를 단일 단위로 처리하고 나중에 사용하기 위해 일치된 텍스트를 캡처할 수 있습니다. 데이터를 추출하고 복잡한 패턴을 만드는 데 기본적입니다.
캡처 그룹
괄호는 일치된 텍스트를 기억하는 캡처 그룹을 만듭니다:
(\d{3})-(\d{3})-(\d{4})
이 패턴은 전화번호와 일치하고 세 개의 그룹을 캡처합니다: 지역 코드, 접두사, 회선 번호. 이러한 캡처된 그룹을 대체 문자열에서 참조하거나 프로그래밍 방식으로 추출할 수 있습니다.
대부분의 프로그래밍 언어에서 캡처된 그룹은 1부터 번호가 매겨집니다. 그룹 0은 항상 전체 일치를 나타냅니다. 예를 들어, JavaScript에서:
const regex = /(\d{3})-(\d{3})-(\d{4})/;
const match = "555-123-4567".match(regex);
// match[0] = "555-123-4567" (전체 일치)
// match[1] = "555" (첫 번째 그룹)
// match[2] = "123" (두 번째 그룹)
// match[3] = "4567" (세 번째 그룹)
비캡처 그룹
때로는 수량자나 교체를 적용하기 위해 그룹화가 필요하지만 일치된 텍스트를 캡처할 필요는 없습니다. 비캡처 그룹에는 (?:...)를 사용하세요:
(?:https?|ftp)://[^\s]+
이것은 프로토콜에 대한 별도의 캡처 그룹을 만들지 않고 http, https 또는 ftp로 시작하는 URL과 일치합니다. 비캡처 그룹은 성능을 향상시키고 캡처 그룹 번호를 깔끔하게 유지합니다.
명명된 캡처 그룹
명명된 그룹은 캡처된 텍스트에 의미 있는 이름을 할당하여 정규 표현식을 더 읽기 쉽고 유지 관리하기 쉽게 만듭니다:
(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})
그룹 1이 연도라는 것을 기억하는 대신 이름으로 참조할 수 있습니다. 구문은 정규 표현식 엔진마다 약간 다르지만 대부분의 최신 구현은 명명된 그룹을 지원합니다.
고급 정규 표현식 기법
기본을 마스터한 후에는 이러한 고급 기법이 복잡한 패턴 매칭 문제를 해결하는 데 도움이 됩니다.
전방탐색 및 후방탐색 어설션
둘러보기 어설션은 현재 위치의 앞이나 뒤에 패턴이 존재하는지 확인하지만 일치에 포함하지는 않습니다:
| 어설션 | 구문 | 설명 |
|---|---|---|
| 긍정 전방탐색 | (?=...) |
패턴이 뒤따르는 경우 일치 |
| 부정 전방탐색 | (?!...) |
패턴이 뒤따르지 않는 경우 일치 |
| 긍정 후방탐색 | (?<=...) |
패턴이 앞에 있는 경우 일치 |
| 부정 후방탐색 | (?<!...) |
패턴이 앞에 없는 경우 일치 |
예: \d+(?= dollars)는 " dollars"가 뒤따르는 숫자와 일치하지만 일치에 " dollars"를 포함하지 않습니다. 이는 특정 컨텍스트에 나타나는 값을 추출하려는 경우에 유용합니다.
역참조
역참조를 사용하면 그룹에 의해 이전에 캡처된 것과 동일한 텍스트를 일치시킬 수 있습니다. 백슬래시 표기법으로 번호가 매겨집니다:
\b(\w+)\s+\1\b
이 패턴은 "the the" 또는 "is is"와 같은 반복된 단어와 일치합니다. \1은 첫 번째 그룹에 의해 캡처된 것을 다시 참조하여 두 단어가 동일하도록 보장합니다.
조건부 패턴
일부 정규 표현식 엔진은 이전 그룹이 일치했는지 여부에 따라 다른 대안과 일치하는 조건부 패턴을 지원합니다:
(a)?b(?(1)c|d)
이것은 선택적 "a"가 있으면 "abc"와 일치하고, 없으면 "bd"와 일치합니다. 조건부 패턴은 강력하지만 정규 표현식을 읽기 어렵게 만들 수 있으므로 신중하게 사용하세요.
프로 팁: 둘러보기 및 조건부와 같은 고급 기능은 모든 정규 표현식 엔진에서 지원되지 않습니다. 호환성을 위해 항상 프로그래밍 언어 또는 도구의 문서를 확인하세요.
실용적인 활용
정규 표현식이 빛나는 실제 시나리오를 즉시 사용할 수 있는 실용적인 예제와 함께 살펴보겠습니다.
이메일 검증
완벽한 이메일 검증은 놀랍도록 복잡하지만