본문 바로가기

C#

Regular Expression (Regex 클래스)

728x90

Regular Expression을 사용하면, 대량의 문자열 데이터에서 특정 패턴을 찾아내거나 특정 패턴 문자열을 다른 것으로 치환하는 등의 일을 쉽게 구현할 수 있다. 따라서 Regular Expression은 Web Crawler나 로그 파싱 등에 매우 유용한 기능이라 할 수 있다.


Regex 문자열 패턴 찾기

Regex 클래스 객체를 생성할 때, 특정 문자 패턴을 파라미터로 전달하며, Regex 객체의 Match() 메서드를 사용하여 특정 패턴이 입력 문자열에 존재하는지 체크하게 된다. Regex.Match() 메서드는 매치된 정보를 갖는 Match 클래스 객체를 리턴한다. 만약 매치된 문자열이 존재하면 Match.Success 속성이 True가 되고, Match.Index 속성을 통해 문자 패턴 위치를 알 수 있다.

// Ex1. 첫 매치 문자열 출력
string str = "서울시 강남구 역삼동 강남아파트";
Regex regex = new Regex("강남");
Match m = regex.Match(str);
if (m.Success)
{
    Debug.WriteLine("{0}:{1}", m.Index, m.Value);
}

Ex1 예제는 [강남]이라는 문자열을 입력문자열(str)에서 찾는 단순한 코드이다. Ex1은 첫 번째 매칭 문자열만을 리턴하는데, 복수개의 매칭 문자열이 존재할 수 있으므로, Ex2에서 처럼 계속 루프를 돌며 NextMatch() 를 호출하여 모든 매칭 데이터를 찾아낼 수 있다.

// Ex2. 매치된 문자열 계속 출력
string str = "서울시 강남구 역삼동 강남아파트";
Regex regex = new Regex("강남");
Match m = regex.Match(str);
while (m.Success)
{
    Debug.WriteLine("{0}:{1}", m.Index, m.Value);
    m = m.NextMatch();
}

 

// Ex3. Matches() 메서드
string str = "서울시 강남구 역삼동 강남아파트";
Regex regex = new Regex("강남");
MatchCollection mc = regex.Matches(str);
foreach (Match m in mc)
{
    Debug.WriteLine("{0}:{1}", m.Index, m.Value);
}

Match클래스는 하나의 매칭 데이터만을 갖는데, 이와 상응하는 컬렉션 클래스로 MatchCollection 클래스가 있다. Ex3 예제는 Regex.Matches() 메서드를 통해 모든 매칭 문자열들을 한꺼번에 MatchCollection 객체로 리턴하는 예를 보여주고 있다.


Regex 메타문자

Regular Expression에는 일반 문자 리터럴(literal)과 특별한 의미를 갖는 메타문자(metacharacter)를 사용할 수 있다. 메타문자의 몇 가지 예로는 다음과 같다.

메타문자 의미
^ 라인의 처음
$ 라인의 마지막
\w 문자(영숫자) [a-zA-Z_0-9]
\s Whitespace (공백, 뉴라인, 탭 등)
* Zero 혹은 그 이상
+ 하나 이상
? Zero 혹은 하나
. Newline을 제외한 한 문자
[  ] 가능한 문자들
[^  ] 가능하지 않은 문자들
[  -  ] 가능 문자 범위
{n,m} 최소 n개, 최대 m개
(  ) 그룹
| 논리 OR
더보기
메타문자 의미
\d 순수한 숫자, 정수값, 0-9
\D 숫자가 아닌 나머지
\W [^a-zA-Z0-9] 영문자와 숫자가 아닌 나머지
\S 공백이 아닌 나머지

Regex 문자열 분리(Split)

Regex 클래스 Split() 메서드는 특정 패턴의 문자열을 기준으로 입력문자열을 분리하는데 사용된다. 예를 들어, 아래 예제는 공백(blank)을 기준으로 입력주소를 분리(split)하여 문자배열을 담아 리턴하는 예이다.

string str = "서울시 강남구 역삼동 강남아파트";

Regex regex = new Regex(" ");
string[] vals = regex.Split(str);
foreach (string s in vals)
{
    Debug.WriteLine(s);
}

Regex - Group 클래스

Regular Expression의 표현식 중에 (  ) 로 표현되는 Group 표현식이 있는데, 이는 특히 유용한 기능을 제공한다. 이 그룹 표현식은 괄호안에 있는 문자열들을 찾아내여 Match 클래스 객체의 Match.Groups 속성에 결과를 넣게 된다. Match.Groups 속성은 GroupCollection 클래스 객체로서 복수의 Group 클래스 객체를 갖는다.

아래 Ex1은 아파트 혹은 APT라는 문자열이 있는 부분의 문자열 위치 정보를 Match.Groups에 저장하고, 이를 출력해보는 예제이다. 여기서 한가지 주의할 점은 Match.Groups는 Match.Groups[1]부터 각 그룹의 결과가 저장된다는 것이다. 패턴이 발견되지 않았을 때에도 Match.Groups[0]는 존재하여 여기에 Group.Success = false를 저장하여 실패를 표현한다.

// Ex1
string str = "강남빌라 역삼아파트 서초APT";
Regex regex = new Regex(@"(아파트|APT)");
MatchCollection mc = regex.Matches(str);
foreach (Match m in mc)
{
    // (Captured) Group은 1부터
    Group g = m.Groups[1];
    Debug.WriteLine("{0}:{1}", g.Index, g.Value);
}

Ex2 예제는 보다 실용적인 예로써 HTML 페이지에서 List 요소값을 모두 찾아내는 예이다.

// Ex2
string str = "<ul><li>홈페이지</li><li>주문메뉴</li></ul>";
Regex regex = new Regex(@"<li>(\w+)</li>");
MatchCollection mc = regex.Matches(str);
foreach (Match m in mc)
{
    Group g = m.Groups[1];
    Debug.WriteLine("{0}:{1}", g.Index, g.Value);                
}

Ex3 예제는 전화번호의 패턴을 찾아내는 예로써 지역번호와 나머지 전화번호를 분리하여 2개의 그룹에 넣는 예를 보여주고 있다.

// Ex3
string str = "02-632-5432; 032-645-7361";
Regex regex = new Regex(@"(\d+)-(\d+-\d+)");
MatchCollection mc = regex.Matches(str);
foreach (Match m in mc)
{
    for (int i = 1; i < m.Groups.Count; i++)
    {
        Group g = m.Groups[i];
        Debug.WriteLine("{0}:{1}", g.Index, g.Value);
    }
}

Regex - Named Group

위의 섹션에서 그룹에 대해 설명했는데, 위에서 복수의 그룹들은 인덱스를 통해서만 접근할 수 있었다. 그런데, Regular Expression에서는 그룹에 이름을 붙여서 사용하는 것(Named Group)이 가능한데, 이는 매우 유용하게 사용될 수 있다. 즉, 각 그룹별로 이름을 붙이면, 여러 그룹들을 사용할 경우 차후에 이름을 통해 그룹 객체를 액세스할 수 있게되어, 코드를 쓰거나 읽는 것이 쉬워진다.

아래 Ex1 예제는 전화번호를 2개의 그룹으로 나누고, 첫부분을 areaNo로 명명하고 나머지는 phoneNo를 명명한 후, 이를 이후 코드에 사용하고 있다. 위의 첫번째 섹션 Ex3과 비교했을 때, 코드를 읽기가 훨씬 쉽다는 것을 알 수 있다.

// Ex1. named group (?<name> )
string str = "02-632-5432; 032-645-7361";
Regex regex = new Regex(@"(?<areaNo>\d+)-(?<phoneNo>\d+-\d+)");
MatchCollection mc = regex.Matches(str);
foreach (Match m in mc)
{                             
    string area = m.Groups["areaNo"].Value;
    string phone = m.Groups["phoneNo"].Value;
    Debug.WriteLine("({0}) {1}", area, phone);
}

Ex2 예제는 웹페이지에 있는 연결 링크(a href) 정보를 Regular Expression을 써서 쉽게 읽어내는 코드이다.

// Ex2
string str = "<div><a href='www.sqlmgmt.com'>SQL Tools</a></div>";
string patt = @"<a[^>]*href\s*=\s*[""']?(?<href>[^""'>]+)[""']?";
Match m = Regex.Match(str, patt);
Group g = m.Groups["href"];
Debug.WriteLine(g.Value);

Regex을 이용한 문자열 치환 - Replce()

Replace() 메서드는 지정된 특정 패턴으로 문자열을 찾아낸 후 이를 다시 파라미터에 지정된 치환 값으로 변경하는 기능을 한다. 예를 들어,

아래 Ex1은 문자열에서 공백이 들어가는 부분을 찾아내어 모두 삭제하는 코드이다. 앞부분 공백을 지우는 ^\s+ 패턴과 뒷부분 공백을 지우는 \s+$ 패턴을 gkaRp | (OR)로 묶어 사용할 수 있다.

// Ex1. 앞 공백 제거
string str = "   서울시 강남구 역삼동 강남아파트 1  ";
string patten = @"^\s+";
// 앞뒤 공백 모두 제거시:  @"^\s+|\s+$";

Regex regex = new Regex(patten);
string s = regex.Replace(str, "");
Debug.WriteLine(s);

Ex2는 ###-###-#### 로 표현된 전화번호를 (###) ###-#### 형식으로 변경하는 에제이다. 이 예제에서 보이는 듯이 기존 패턴의 내용을 그룹명으로 지정하면 이를 ${그룹명} 형식으로 치환 표현식에서 지정할 수 있다.

// Ex2
string str = "02-632-5432; 032-645-7361";
string patten = @"(?<areaNo>\d+)-(?<phoneNo>\d+-\d+)";
Regex regex = new Regex(patten);
string s = regex.Replace(str, @"(${areaNo}) ${phoneNo}");
Debug.WriteLine(s);

[출처]

https://www.csharpstudy.com/Practical/Prac-regex-1.aspx

https://www.csharpstudy.com/Practical/Prac-regex-2.aspx

https://durubiz.tistory.com/entry/C-%EC%97%90%EC%84%9C-%EC%A0%95%EA%B7%9C%ED%91%9C%ED%98%84%EC%8B%9D-RegexIsMatch-%EC%9D%B4%EC%9A%A9#google_vignette

728x90