소개 대표 사이트 카테고리 커뮤니티 페이지 만들기
본문 바로가기

정규표현식(Regular Expression) 자동화, 로그 분석·보안 필터링·유효성 검사

728x90

정규표현식(Regular Expression, 줄여서 Regex 또는 RegExp)은 문자열의 패턴을 표현하는 특수한 문자열입니다. 텍스트에서 특정 패턴을 검색하고, 추출하고, 치환하는 데 사용되는 강력한 도구입니다.

  • 복잡한 문자열 패턴을 간결하게 표현
  • 거의 모든 프로그래밍 언어에서 지원
  • 검색, 유효성 검사, 추출, 치환 등에 활용
300x250

기본 문법과 구성 요소

메타 문자(Meta Characters)

문자 설명 예시
. 임의의 한 문자 a.c → abc, a1c, a@c
* 앞 문자가 0개 이상 ab*c → ac, abc, abbc
+ 앞 문자가 1개 이상 ab+c → abc, abbc (ac는 불가)
? 앞 문자가 0개 또는 1개 ab?c → ac, abc
^ 문자열의 시작 ^Hello → Hello로 시작하는 문자열
$ 문자열의 끝 world$ → world로 끝나는 문자열
[] 문자 클래스 [abc] → a, b, c 중 하나
[^] 부정 문자 클래스 [^abc] → a, b, c가 아닌 문자
| OR 연산자 cat|dog → cat 또는 dog
() 그룹화 (ab)+ → ab, abab, ababab

특수 이스케이프 시퀀스

시퀀스 설명 예시
\d 숫자 [0-9] \d{3} → 123, 456
\D 숫자가 아닌 문자 \D+ → abc, xyz
\w 단어 문자 [a-zA-Z0-9_] \w+ → hello, test_123
\W 단어 문자가 아닌 문자 \W+ → @#$, !!!
\s 공백 문자 \s+ → 스페이스, 탭, 개행
\S 공백이 아닌 문자 \S+ → hello, 123
\b 단어 경계 \bword\b → 독립된 word
\n 개행 문자 -
\t 탭 문자 -

수량자(Quantifiers)

수량자 설명 예시
{n} 정확히 n개 \d{4} → 1234
{n,} n개 이상 \d{2,} → 12, 123, 1234
{n,m} n개 이상 m개 이하 \d{2,4} → 12, 123, 1234
*? 0개 이상 (최소 매칭) <.*?> → HTML 태그
+? 1개 이상 (최소 매칭) .+? → 최소 매칭

분야별 활용 사례

웹 개발 / 프론트엔드

이메일 유효성 검사

const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
const isValid = emailRegex.test("user@example.com");

전화번호 형식 검사

// 한국 휴대폰 번호
const phoneRegex = /^01[0-9]-?\d{3,4}-?\d{4}$/;
// 010-1234-5678, 01012345678 모두 매칭

// 국제 전화번호
const intlPhoneRegex = /^\+\d{1,3}[-.\s]?\(?\d{1,4}\)?[-.\s]?\d{1,4}[-.\s]?\d{1,9}$/;

URL 추출

const urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/gi;
const urls = text.match(urlRegex);

백엔드 / 서버 개발

로그 파일 분석 (Apache/Nginx)

import re

# Apache 액세스 로그 파싱
log_pattern = r'(\d+\.\d+\.\d+\.\d+) - - \[(.*?)\] "(.*?)" (\d+) (\d+)'
log_line = '192.168.1.1 - - [10/Oct/2023:13:55:36 +0700] "GET /index.html HTTP/1.1" 200 2326'

match = re.match(log_pattern, log_line)
if match:
    ip, timestamp, request, status_code, size = match.groups()

SQL 인젝션 방지

# 위험한 SQL 패턴 감지
dangerous_patterns = [
    r"(\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION)\b)",
    r"(--|\#|\/\*|\*\/)",
    r"(\bOR\b\s*\d+\s*=\s*\d+)",
    r"(\bAND\b\s*\d+\s*=\s*\d+)"
]

def check_sql_injection(user_input):
    for pattern in dangerous_patterns:
        if re.search(pattern, user_input, re.IGNORECASE):
            return True
    return False

API 엔드포인트 라우팅

# Flask/Django 스타일 라우팅
routes = [
    (r'^/users/(\d+)$', 'get_user'),
    (r'^/posts/(\d+)/comments$', 'get_comments'),
    (r'^/api/v(\d+)/(.+)$', 'api_handler')
]

데이터 처리 / 분석

CSV 데이터 정제

# 쉼표가 포함된 CSV 필드 처리
csv_pattern = r'(?:^|,)("(?:[^"]+|"")*"|[^,]*)'

# 날짜 형식 표준화
date_patterns = {
    r'(\d{4})/(\d{2})/(\d{2})': r'\1-\2-\3',  # YYYY/MM/DD → YYYY-MM-DD
    r'(\d{2})/(\d{2})/(\d{4})': r'\3-\1-\2',  # MM/DD/YYYY → YYYY-MM-DD
    r'(\d{2})-(\d{2})-(\d{4})': r'\3-\1-\2'   # MM-DD-YYYY → YYYY-MM-DD
}

텍스트 마이닝

# 해시태그 추출
hashtag_pattern = r'#[가-힣a-zA-Z0-9_]+'

# 멘션 추출
mention_pattern = r'@[a-zA-Z0-9_]+'

# 한글 단어 추출
korean_word_pattern = r'[가-힣]+'

설정 파일 / 구성 관리

.env 파일 파싱

# KEY=VALUE 형식 파싱
env_pattern = r'^([A-Z_]+)=(.*)$'

def parse_env_file(content):
    env_vars = {}
    for line in content.split('\n'):
        match = re.match(env_pattern, line)
        if match:
            key, value = match.groups()
            env_vars[key] = value.strip('"\'')
    return env_vars

nginx.conf 파싱

# location 블록 추출
location_pattern = r'location\s+(.*?)\s*\{([^}]*)\}'

# upstream 서버 추출
upstream_pattern = r'server\s+([^;]+);'

보안 / 유효성 검사

비밀번호 강도 검사

const passwordRules = {
    minLength: /.{8,}/,
    hasUpperCase: /[A-Z]/,
    hasLowerCase: /[a-z]/,
    hasNumber: /\d/,
    hasSpecialChar: /[!@#$%^&*(),.?":{}|<>]/
};

function validatePassword(password) {
    return Object.entries(passwordRules).every(([rule, regex]) => 
        regex.test(password)
    );
}

XSS 방지

// 위험한 HTML 태그 제거
const dangerousTagsRegex = /<script[^>]*>.*?<\/script>|<iframe[^>]*>.*?<\/iframe>/gi;
const sanitizedHtml = userInput.replace(dangerousTagsRegex, '');

파일 처리 / 시스템 관리

파일명 패턴 매칭

# Bash에서 find와 함께 사용
find . -regex '.*\.\(jpg\|png\|gif\)$'

# Python에서 파일 필터링
import re
import os

def find_files_by_pattern(directory, pattern):
    regex = re.compile(pattern)
    matched_files = []

    for root, dirs, files in os.walk(directory):
        for file in files:
            if regex.match(file):
                matched_files.append(os.path.join(root, file))

    return matched_files

# 예: 날짜가 포함된 백업 파일 찾기
backup_files = find_files_by_pattern('.', r'backup_\d{8}_\d{6}\.tar\.gz$')

정규표현식 손쉽게 생성하는 방법

온라인 도구 활용

1. Regex101 (https://regex101.com)

  • 실시간 매칭 결과 확인
  • 상세한 설명 제공
  • 여러 언어의 정규식 엔진 지원
  • 저장 및 공유 기능

2. RegExr (https://regexr.com)

  • 시각적 표현
  • 치트시트 제공
  • 커뮤니티 패턴 라이브러리

3. Regex Visualizer (https://regexper.com)

  • 정규식을 시각적 다이어그램으로 변환
  • 복잡한 패턴 이해에 유용

AI 도구 활용

# ChatGPT나 Claude에게 요청하는 예시
"""
다음 조건을 만족하는 정규표현식을 만들어주세요:
- 한국 주민등록번호 형식 (######-#######)
- 앞 6자리는 생년월일 (YYMMDD)
- 뒤 7자리 중 첫 번째는 1-4 중 하나
"""

# 결과: ^\d{6}-[1-4]\d{6}$

패턴 빌더 라이브러리

JavaScript - VerbalExpressions

const VerEx = require('verbal-expressions');

const urlRegex = VerEx()
    .startOfLine()
    .then('http')
    .maybe('s')
    .then('://')
    .maybe('www.')
    .anythingBut(' ')
    .endOfLine();

Python - re-builder

from rebuilder import ReBuilder

rb = ReBuilder()
email_pattern = (rb
    .start()
    .one_or_more.word()
    .literal('@')
    .one_or_more.word()
    .literal('.')
    .between(2, 4).letters()
    .end()
    .build()
)

단계별 구축 전략

1단계: 기본 패턴 작성

// 목표: 이메일 주소 매칭
// 시작: 기본 구조
const step1 = /.+@.+\..+/;

2단계: 세부 규칙 추가

// 허용 문자 지정
const step2 = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/;

3단계: 경계 조건 추가

// 시작과 끝 명시
const step3 = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

4단계: 예외 처리

// 특수 케이스 고려
const final = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/i;

실전 팁과 최적화

성능 최적화

1. 불필요한 캡처 그룹 피하기

// 나쁜 예
/(https?):\/\/(www\.)?([a-z]+\.[a-z]+)/

// 좋은 예 (비캡처 그룹 사용)
/(?:https?):\/\/(?:www\.)?([a-z]+\.[a-z]+)/

2. 구체적인 문자 클래스 사용

// 나쁜 예
/.*/  // 모든 문자

// 좋은 예
/[^,]*/  // 쉼표를 제외한 문자

3. 앵커 사용으로 검색 범위 제한

// 나쁜 예
/admin/  // 문자열 전체 검색

// 좋은 예
/^admin/  // 시작 부분만 검색

가독성 향상

1. 명명된 캡처 그룹 사용

// ES2018+
const dateRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = dateRegex.exec('2023-10-15');
console.log(match.groups.year);  // 2023

2. 주석과 공백 활용 (x 플래그)

# Python
pattern = re.compile(r"""
    ^                   # 시작
    (?P<protocol>https?)  # 프로토콜
    ://                 # 구분자
    (?P<domain>[^/]+)   # 도메인
    (?P<path>/.*)?      # 경로 (선택적)
    $                   # 끝
""", re.VERBOSE)

디버깅 전략

1. 단계별 테스트

function debugRegex(pattern, testCases) {
    testCases.forEach(testCase => {
        const match = pattern.test(testCase);
        console.log(`"${testCase}": ${match ? '✓' : '✗'}`);
    });
}

2. 부분 패턴 분리

// 복잡한 패턴을 작은 단위로 분리
const protocolPattern = /https?/;
const domainPattern = /[a-zA-Z0-9.-]+/;
const pathPattern = /\/[^ ]*/;

// 조합
const urlPattern = new RegExp(
    `^${protocolPattern.source}://${domainPattern.source}${pathPattern.source}?$`
);

언어별 정규표현식 차이점

JavaScript vs Python

// JavaScript
const pattern = /\d+/g;  // 전역 플래그
const matches = text.match(pattern);

// Python
import re
pattern = r'\d+'
matches = re.findall(pattern, text)

Java 특수성

// 이스케이프 문자 이중 처리
Pattern pattern = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");

// 여러 줄 모드
Pattern multiline = Pattern.compile("^test$", Pattern.MULTILINE);

PHP 구분자

// 다양한 구분자 사용 가능
preg_match('/pattern/', $text);
preg_match('#pattern#', $text);
preg_match('~pattern~', $text);

자주 사용되는 패턴 모음

한국어 관련

// 한글만
/^[가-힣]+$/

// 한글과 공백
/^[가-힣\s]+$/

// 한국 우편번호 (새 형식)
/^\d{5}$/

// 한국 사업자등록번호
/^\d{3}-\d{2}-\d{5}$/

웹 관련

// 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]?)$/

// 헥스 컬러 코드
/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/

// 유튜브 비디오 ID
/(?:youtube\.com\/watch\?v=|youtu\.be\/)([^&\n?#]+)/

데이터 유효성

// 신용카드 번호 (간단)
/^\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}$/

// ISBN-13
/^(?:ISBN(?:-13)?:?\ ?)?(?=[0-9]{13}$|(?=(?:[0-9]+[-\ ]){4})[-\ 0-9]{17}$)97[89][-\ ]?[0-9]{1,5}[-\ ]?[0-9]+[-\ ]?[0-9]+[-\ ]?[0-9]$/

// MAC 주소
/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/

정규표현식 사용 시 주의사항

1. 과도한 복잡성 피하기

  • 너무 복잡한 정규식은 유지보수가 어려움
  • 필요시 여러 개의 간단한 패턴으로 분리

2. 성능 고려

  • 백트래킹이 많이 발생하는 패턴 주의
  • 큰 텍스트에서는 정규식 대신 파싱 라이브러리 고려

3. 보안 이슈

  • 사용자 입력을 정규식 패턴으로 사용 금지 (ReDoS 공격)
  • 유효성 검사는 정규식만으로 충분하지 않을 수 있음

4. 국제화 고려

  • 유니코드 문자 처리
  • 다양한 언어와 문자 체계 지원

정규표현식은 강력한 도구이지만, 적절히 사용해야 합니다. 간단한 문자열 처리는 내장 함수로, 복잡한 파싱은 전용 파서로 처리하는 것이 좋을 수 있습니다. 정규표현식은 그 중간 영역에서 빛을 발합니다. 항상 가독성과 유지보수성을 고려하여 작성하고, 충분한 테스트를 통해 예상치 못한 경우를 대비하세요.

728x90
그리드형(광고전용)

댓글