정규표현식, 패턴 하나로 텍스트를 다루는 법

정규표현식의 메타 문자·문자 클래스·수량자부터 정제·변환·치환·삭제 기법, 로그 분석·데이터 검증·ETL 활용 사례까지 정리한다

2026-08-14 · 최초 발행 2025-05-23

이메일 주소가 맞는지 확인하고, HTML 태그를 걷어내고, 로그에서 IP만 뽑아내는 일. 형태는 제각각이지만 전부 정규표현식(Regular Expression) 하나로 처리된다. 문자열 안에서 패턴을 정의하고 그 패턴에 따라 찾거나 바꾸는 이 도구는 소프트웨어 개발과 데이터 처리 전반에서 반복적으로 쓰인다.

패턴을 구성하는 요소들

일반 텍스트 문자는 그대로 매칭된다 — apple은 문자열 내 "apple"을 찾는다. 여기에 특별한 의미를 가진 메타 문자가 붙으면 패턴이 된다: .은 임의의 한 문자, ^는 문자열의 시작, $는 문자열의 끝, *는 앞 요소의 0번 이상 반복, +는 1번 이상 반복, ?는 0 또는 1번 등장, |는 OR 연산자(대안 패턴), \는 이스케이프 문자를 뜻한다.

문자 클래스는 특정 범위의 문자 하나를 매칭한다: [abc]는 a, b, c 중 하나, [^abc]는 a, b, c를 제외한 문자, [a-z]는 a부터 z까지, [0-9]는 숫자와 매칭된다. 자주 쓰는 조합은 미리 정의되어 있다 — \d는 숫자([0-9]와 동일), \D는 숫자가 아닌 문자, \w는 단어 문자([a-zA-Z0-9_]와 동일), \W는 단어 문자가 아닌 것, \s는 공백, \S는 공백이 아닌 문자와 매칭된다.

반복 횟수는 수량자로 지정한다: {n}은 정확히 n번, {n,}은 n번 이상, {n,m}은 n번 이상 m번 이하 반복을 뜻한다.

정규표현식으로 하는 텍스트 처리

정제(Cleaning)는 텍스트에서 불필요한 문자나 형식을 제거해 깨끗한 데이터로 바꾸는 작업이다. HTML 태그 제거(<.*?>), 이메일 주소 검증(^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$), 불필요한 공백을 단일 공백으로 치환(\s+)하는 것이 대표적이다.

// HTML 태그 제거 예시
const htmlString = "<p>정규표현식 <strong>예제</strong> 입니다.</p>";
const cleanText = htmlString.replace(/<.*?>/g, "");
console.log(cleanText); // "정규표현식 예제 입니다."

변환(Transformation)은 텍스트의 형식을 다른 형태로 바꾼다. 날짜 형식 변환((\d{4})-(\d{2})-(\d{2})$2/$3/$1), 전화번호 형식 통일((\d{3})(\d{4})(\d{4})$1-$2-$3), 패턴 매칭 후 대소문자 변환 등이 여기 속한다.

# 날짜 형식 변환 예시
import re
date_string = "2023-11-15"
formatted_date = re.sub(r'(\d{4})-(\d{2})-(\d{2})', r'\2/\3/\1', date_string)
print(formatted_date)  # "11/15/2023"

치환(Replacement)은 특정 패턴을 다른 문자열로 대체한다. 비속어를 별표(*) 등으로 치환하거나, 텍스트 내 URL 패턴을 HTML 링크 태그로 바꾸거나, 약어를 전체 단어로 확장하는 데 쓴다.

// 비속어 필터링 예시
String text = "이 부분은 ㅅㅂ 비속어를 포함합니다.";
String filtered = text.replaceAll("ㅅㅂ", "**");
System.out.println(filtered); // "이 부분은 ** 비속어를 포함합니다."

삭제(Deletion)는 특정 패턴에 해당하는 문자를 완전히 없앤다. 특수문자 제거([^\w\s]), 숫자 제거(\d), 주석 제거(//.*$ 또는 /\*.*?\*/)가 대표적이다.

# 특수문자 제거 예시
import re
messy_text = "안녕하세요! 제 이메일은 user@example.com이고, 전화번호는 010-1234-5678입니다."
clean_text = re.sub(r'[^\w\s가-힣]', '', messy_text)
print(clean_text)  # "안녕하세요 제 이메일은 user examplecom이고 전화번호는 01012345678입니다"

로그 분석부터 웹 스크래핑까지

로그 파일 분석에서는 특정 패턴의 에러 메시지를 추출하고, 시간대별 로그 엔트리를 그룹화하며, IP 주소 패턴을 매칭해 분석한다.

# 로그 파일에서 IP 주소 추출
grep -E "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" access.log

데이터 검증에서는 이메일 주소, 비밀번호 복잡성, 전화번호 형식을 확인하는 데 쓴다.

// 강력한 비밀번호 검증 예시
const passwordRegex =
  /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
const isValidPassword = passwordRegex.test("Example1!");
console.log(isValidPassword); // true or false

ETL(추출-변환-적재) 과정에서는 서로 다른 소스의 데이터 형식을 통일하고 불필요한 데이터를 걸러낸다.

# CSV 파일의 특정 열 데이터 정제 예시
import pandas as pd
import re

df = pd.read_csv('data.csv')
# 전화번호 형식 통일
df['phone'] = df['phone'].apply(lambda x: re.sub(r'(\d{3})[\s.-]?(\d{4})[\s.-]?(\d{4})', r'\1-\2-\3', str(x)))
# 이메일 유효성 검증
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
df['valid_email'] = df['email'].apply(lambda x: bool(re.match(email_pattern, str(x))))

웹 스크래핑에서는 HTML 페이지에서 필요한 정보를 추출하고, 구조화되지 않은 텍스트에서 패턴을 인식한다.

# 웹 페이지에서 이메일 주소 추출 예시
import re
import requests

response = requests.get('https://example.com')
emails = re.findall(r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', response.text)
print(emails)  # 페이지에서 발견된 이메일 주소 목록

패턴 하나로 성능이 갈린다

탐욕적 수량자(*, +, {n,m})는 가능한 많은 문자를 매칭하고, 게으른 수량자(*?, +?, {n,m}?)는 가능한 적은 문자를 매칭한다. 같은 문자열이라도 어느 쪽을 쓰느냐에 따라 결과가 달라진다.

// 탐욕적 vs 게으른 예시
문자열: "<div>내용1</div><div>내용2</div>"

탐욕적 패턴: <div>.*</div>
결과: "<div>내용1</div><div>내용2</div>" (전체 매칭)

게으른 패턴: <div>.*?</div>
결과: "<div>내용1</div>" 그리고 "<div>내용2</div>" (개별 매칭)

^$ 같은 앵커를 활용하면 불필요한 매칭 시도를 막아 정확한 시작점과 끝점을 지정할 수 있고, 과도한 역참조와 중첩 그룹은 복잡도를 높여 성능을 떨어뜨리므로 가능한 단순화된 패턴을 쓰는 것이 좋다.

패턴을 검증할 때는 Regex101(https://regex101.com/), RegExr(https://regexr.com/), Debuggex(https://www.debuggex.com/) 같은 온라인 도구를 활용할 수 있다. 언어별로는 JavaScript의 RegExp 객체, Python의 re 모듈, Java의 java.util.regex 패키지, PHP의 preg_* 함수들이 정규표현식을 구현한다.

매칭 성공매칭 실패원본 텍스트정규표현식 패턴 정의패턴 매칭텍스트 처리오류 처리/건너뛰기정제변환치환삭제결과 텍스트

쓸 때 주의할 것들

복잡한 패턴은 주석이나 변수로 나누어 관리하고, 의미 있는 이름으로 패턴 변수를 정의하는 편이 유지보수에 유리하다. 사용자 입력을 직접 정규표현식에 사용하면 ReDoS(정규표현식 서비스 거부 공격) 위험이 있으므로 입력 검증과 패턴 복잡도 제한이 필요하다. 멀티라인 텍스트를 다룰 때는 m 플래그로 각 줄의 시작과 끝을 처리해야 하고, 도트(.)가 기본적으로 줄바꿈 문자를 매칭하지 않는다는 점도 알아둬야 한다. 다국어를 지원하려면 유니코드 문자 클래스를 쓰되, 정규표현식 엔진마다 유니코드 지원 범위가 다르다는 점을 인지해야 한다.

정규표현식은 문자열의 정제, 변환, 치환, 삭제 등 다양한 작업을 간결하게 수행하게 해주는 도구이며, 소프트웨어 개발과 데이터 분석, 시스템 관리 전반에서 쓰인다. 다만 복잡한 패턴은 가독성과 성능 문제를 낳을 수 있으므로 적절한 수준에서 사용하고, 필요하면 테스트 도구로 검증하는 습관이 중요하다.

정규표현식Regular Expression패턴 매칭텍스트 처리