개발/C# .NET
C#에서 정규식(Regular Expression) 완벽 가이드
xwing
2025. 5. 26. 11:23
정규식(Regular Expression, Regex)은 문자열 패턴을 매칭하고 조작하는 강력한 도구입니다. C#에서는 System.Text.RegularExpressions 네임스페이스를 통해 정규식 기능을 제공하며, 문자열 검증, 추출, 치환 등 다양한 작업에 활용할 수 있습니다.
정규식 기본 사용법
1. Regex 클래스 기본 사용
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string text = "안녕하세요! 제 전화번호는 010-1234-5678입니다.";
string pattern = @"\d{3}-\d{4}-\d{4}";
Regex regex = new Regex(pattern);
Match match = regex.Match(text);
if (match.Success)
{
Console.WriteLine($"전화번호 발견: {match.Value}");
}
}
}
2. 정적 메서드 사용
string text = "이메일: user@example.com";
string pattern = @"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}";
// 정적 메서드를 사용한 매칭
bool isMatch = Regex.IsMatch(text, pattern);
Match match = Regex.Match(text, pattern);
Console.WriteLine($"이메일 매칭: {isMatch}");
Console.WriteLine($"발견된 이메일: {match.Value}");
주요 정규식 패턴
기본 메타문자
패턴 설명 예제
. | 임의의 한 문자 (개행 제외) | a.c → "abc", "axc" |
* | 0회 이상 반복 | ab*c → "ac", "abc", "abbc" |
+ | 1회 이상 반복 | ab+c → "abc", "abbc" |
? | 0회 또는 1회 | colou?r → "color", "colour" |
^ | 문자열 시작 | ^Hello → "Hello world" |
$ | 문자열 끝 | world$ → "Hello world" |
문자 클래스
// 숫자 매칭
string pattern1 = @"\d+"; // \d는 [0-9]와 동일
string pattern2 = @"[0-9]+"; // 직접 정의
// 영문자 매칭
string pattern3 = @"[a-zA-Z]+"; // 영문자
string pattern4 = @"\w+"; // 단어 문자 (영문자, 숫자, 언더스코어)
// 공백 매칭
string pattern5 = @"\s+"; // 공백, 탭, 개행 등
실용적인 예제들
1. 이메일 주소 검증
public static bool IsValidEmail(string email)
{
string pattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
return Regex.IsMatch(email, pattern);
}
// 사용 예시
string[] emails = { "test@example.com", "invalid-email", "user.name+tag@domain.co.kr" };
foreach (string email in emails)
{
Console.WriteLine($"{email}: {(IsValidEmail(email) ? "유효" : "무효")}");
}
2. 전화번호 포맷 변환
public static string FormatPhoneNumber(string phoneNumber)
{
// 숫자만 추출
string digitsOnly = Regex.Replace(phoneNumber, @"[^\d]", "");
// 11자리 휴대폰 번호 포맷팅
if (digitsOnly.Length == 11)
{
return Regex.Replace(digitsOnly, @"(\d{3})(\d{4})(\d{4})", "$1-$2-$3");
}
return phoneNumber; // 포맷팅 불가능한 경우 원본 반환
}
// 사용 예시
string[] phones = { "01012345678", "010 1234 5678", "010-1234-5678" };
foreach (string phone in phones)
{
Console.WriteLine($"{phone} → {FormatPhoneNumber(phone)}");
}
3. HTML 태그 제거
public static string RemoveHtmlTags(string html)
{
return Regex.Replace(html, @"<[^>]*>", "");
}
// 사용 예시
string htmlText = "<p>안녕하세요! <strong>강조</strong>된 텍스트입니다.</p>";
string plainText = RemoveHtmlTags(htmlText);
Console.WriteLine(plainText); // "안녕하세요! 강조된 텍스트입니다."
4. 단어 추출 및 개수 세기
public static Dictionary<string, int> CountWords(string text)
{
var wordCounts = new Dictionary<string, int>();
// 단어 패턴 매칭 (영문자만)
MatchCollection matches = Regex.Matches(text.ToLower(), @"\b[a-z]+\b");
foreach (Match match in matches)
{
string word = match.Value;
wordCounts[word] = wordCounts.ContainsKey(word) ? wordCounts[word] + 1 : 1;
}
return wordCounts;
}
// 사용 예시
string text = "The quick brown fox jumps over the lazy dog. The dog was really lazy.";
var wordCounts = CountWords(text);
foreach (var kvp in wordCounts)
{
Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}
고급 기능
1. 그룹 캡처 사용
string text = "생년월일: 1990-05-15";
string pattern = @"(\d{4})-(\d{2})-(\d{2})";
Match match = Regex.Match(text, pattern);
if (match.Success)
{
Console.WriteLine($"전체 매칭: {match.Value}");
Console.WriteLine($"년: {match.Groups[1].Value}");
Console.WriteLine($"월: {match.Groups[2].Value}");
Console.WriteLine($"일: {match.Groups[3].Value}");
}
2. 명명된 그룹 사용
string text = "사용자: john_doe, 나이: 25";
string pattern = @"사용자: (?<username>\w+), 나이: (?<age>\d+)";
Match match = Regex.Match(text, pattern);
if (match.Success)
{
Console.WriteLine($"사용자명: {match.Groups["username"].Value}");
Console.WriteLine($"나이: {match.Groups["age"].Value}");
}
3. 조건부 치환
// 대소문자 변환 예제
string text = "Hello World! This is a TEST.";
string result = Regex.Replace(text, @"\b[A-Z]+\b",
match => match.Value.ToLower());
Console.WriteLine(result); // "Hello World! This is a test."
성능 최적화 팁
1. 컴파일된 정규식 사용
// 반복적으로 사용되는 패턴은 컴파일하여 성능 향상
private static readonly Regex EmailRegex = new Regex(
@"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
RegexOptions.Compiled);
public static bool IsValidEmailOptimized(string email)
{
return EmailRegex.IsMatch(email);
}
2. 타임아웃 설정
// 복잡한 패턴에서 무한 루프 방지
try
{
var regex = new Regex(pattern, RegexOptions.None, TimeSpan.FromSeconds(1));
Match match = regex.Match(input);
}
catch (RegexMatchTimeoutException)
{
Console.WriteLine("정규식 매칭 시간 초과");
}
일반적인 패턴 모음
public static class CommonPatterns
{
// 이메일
public static readonly string Email = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
// 한국 휴대폰 번호
public static readonly string KoreanPhone = @"^010-\d{4}-\d{4}$";
// URL
public static readonly string Url = @"https?://[^\s]+";
// 숫자만
public static readonly string NumbersOnly = @"^\d+$";
// 영문자와 숫자만
public static readonly string AlphaNumeric = @"^[a-zA-Z0-9]+$";
// 한국 우편번호 (새 형식)
public static readonly string KoreanZipCode = @"^\d{5}$";
// 비밀번호 (최소 8자, 영문자와 숫자 포함)
public static readonly string Password = @"^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$";
}
주의사항 및 베스트 프랙티스
1. Verbatim String 사용
// 권장: @ 접두사 사용으로 백슬래시 이스케이프 방지
string pattern = @"\d{3}-\d{4}-\d{4}";
// 비권장: 이스케이프 문자로 인한 복잡성
string pattern2 = "\\d{3}-\\d{4}-\\d{4}";
2. 정규식 검증 도구 활용
복잡한 정규식을 작성할 때는 온라인 도구를 활용하여 패턴을 테스트하고 검증하는 것이 좋습니다. regex101.com과 같은 사이트에서 실시간으로 패턴을 테스트할 수 있습니다.
3. 성능 고려사항
- 정규식은 강력하지만 복잡한 패턴은 성능에 영향을 줄 수 있습니다
- 단순한 문자열 연산으로 해결 가능한 경우는 String 클래스의 메서드를 우선 고려하세요
- 반복적으로 사용되는 패턴은 RegexOptions.Compiled 옵션을 사용하세요
마무리
C#의 정규식은 문자열 처리에서 매우 유용한 도구입니다. 기본적인 패턴 매칭부터 복잡한 데이터 추출까지 다양한 용도로 활용할 수 있습니다. 하지만 정규식의 복잡성으로 인해 가독성과 유지보수성을 고려하여 적절히 사용하는 것이 중요합니다.
정규식을 마스터하면 문자열 처리 작업의 효율성을 크게 향상시킬 수 있으니, 다양한 패턴을 연습해보시기 바랍니다.