지난 글에 이어 정규 표현식을 마저 정리해보았다.
1. 정규 표현식 익혀보기
1-1. 문자 클래스
\ 뒤에 특정 알파벳은 입력하게되면 특정한 한 문자를 나타내는 문자 클래스를 나타내게 된다. \w, \W, \s, \S, \d, \D 와 같은 문자클래스가 있다.
같은 알파벳의 소문자와 대문자의 경우 서로 반대의 의미가 된다. 예시로 살펴보는 것이 이해가 빠르다.
\w는 한 개의 알파벳 또는 한 개의 숫자 또는 언더바 _ 와 동일하다. 따라서 [a-zA-Z0-9_]와 동일하다.
사례 1
소스 : A1 B2 c3 d_4 e:5 ffGG77--___--
정규 표현식 : \w
첫 번째 매치
A1 B2 c3 d_4 e:5 ffGG77--___--
전체 매치
A1 B2 c3 d_4 e:5 ffGG77--___--
알파벳, 숫자, 언더바와 매치된 것을 볼 수 있다.
사례 2
소스 : A1 B2 c3 d_4 e:5 ffGG77--___--
정규 표현식 : \w*
첫 번째 매치
A1 B2 c3 d_4 e:5 ffGG77--___--
전체 매치
A1 B2 c3 d_4 e:5 ffGG77--___--
알파벳, 숫자, 언더바 중에서 0개 이상인 부분과 매치되게 된다.
사례 3
소스 : A1 B2 c3 d_4 e:5 ffGG77--___--
정규 표현식 : [a-z]\w*
첫 번째 매치
A1 B2 c3 d_4 e:5 ffGG77--___--
전체 매치
A1 B2 c3 d_4 e:5 ffGG77--___--
소문자 알파벳 뒤에 알파벳,숫자,언더바가 0개 이상있으면 매치되게 된다.
사례 4
소스 : A1 B2 c3 d_4 e:5 ffGG77--___--
정규 표현식 : \w{5}
첫 번째 매치
A1 B2 c3 d_4 e:5 ffGG77--___--
전체 매치
A1 B2 c3 d_4 e:5 ffGG77--___--
알파벳, 숫자, 언더바가 정확히 5개 연속이어야 매치된다.
사례 5
소스 : A1 B2 c3 d_4 e:5 ffGG77--___--
정규 표현식 : [a-zA-Z0-9_]
첫 번째 매치
A1 B2 c3 d_4 e:5 ffGG77--___--
전체 매치
A1 B2 c3 d_4 e:5 ffGG77--___--
\w와 [A-z0-9_] 는 같다. 따라서 사례1과 완전히 동일하다.
같은 알파벳의 소문자와 대문자의 경우 서로 반대의 의미가 된다고 했다. 따라서 \W는 \w랑 매치되지 않는 문자들로만 이루어져 있다. 따라서 [^a-zA-Z0-9_]와 동일하며 알파벳, 숫자, 언더바가 아닌 한 문자가 매치된다.
사례 1
소스 : AS _34:AS11.23 @#$ %12^*
정규 표현식 : \W
첫 번째 매치
AS _34:AS11.23 @#$ %12^*
전체 매치
AS _34:AS11.23 @#$ %12^*
알파벳, 숫자, 언더바가 아닌 모든 문자들인 공백, 기호들과 매치된 것을 볼 수 있다.
사례 2
소스 : AS _34:AS11.23 @#$ %12^*
정규 표현식 : \w
첫 번째 매치
AS _34:AS11.23 @#$ %12^*
전체 매치
AS _34:AS11.23 @#$ %12^*
\w와 \W의 전체 매치를 보게되면 완전히 반대로 매치된 것을 볼 수 있다.
사례 3
소스 : AS _34:AS11.23 @#$ %12^*
정규 표현식 : [^a-zA-Z0-9_]
첫 번째 매치
AS _34:AS11.23 @#$ %12^*
전체 매치
AS _34:AS11.23 @#$ %12^*
\W와 [^a-zA-Z0-9_]는 같기 때문에 사례 1과 완전히 동일한 결과가 나오게 된다.
\s는 스페이스, 줄바꿈, 탭과 같은 모든 공백 문자와 매치된다. \S는 공백문자가 아닌 모든 것과 매치된다.
사례 1
소스 :
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
정규 표현식 : \s
첫 번째 매치
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
전체 매치
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
공백에 매치된 것을 볼 수 있다.
사례 2
소스 :
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
정규 표현식 : \S
첫 번째 매치
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
전체 매치
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
공백이 아닌 모든 문자들과 매치된 것을 볼 수 있다.
\d는 모든 숫자와 매치된다. \D는 반대로 숫자가 아닌 모든 문자와 매치된다. \d는 [0-9]와 같고 \D는 [^0-9]와 같다.
사례 1
소스 : Page 123; publihsed: 1234 id=12#24@112
정규 표현식 : \d
첫 번째 매치
Page 123; publihsed: 1234 id=12#24@112
전체 매치
Page 123; publihsed: 1234 id=12#24@112
숫자들과 매치된 것을 볼 수 있다.
사례 2
소스 : Page 123; publihsed: 1234 id=12#24@112
정규 표현식 : \D
첫 번째 매치
Page 123; publihsed: 1234 id=12#24@112
전체 매치
Page 123; publihsed: 1234 id=12#24@112
\D는 숫자를 제외한 모든 문자들과 매치된다.
사례 3
소스 : Page 123; publihsed: 1234 id=12#24@112
정규 표현식 : [0-9]
첫 번째 매치
Page 123; publihsed: 1234 id=12#24@112
전체 매치
Page 123; publihsed: 1234 id=12#24@112
\d와 [0-9]는 같기 때문에 사례 1과 완전히 동일한 결과가 나온다.
1-2. 앵커
이미 초반부에 위치 기준으로 매칭되는 앵커인 ^와 $에 대해 살펴보았었다. \와 알파벳이 함께 쓰여 앵커로 사용되는 것들을 살펴보자.
\b 는 단어의 경계와 매치된다. 단어의 경계는 한쪽에는 \w가 한쪽에는 \W가 있는 곳으로 정의된다. 좀 더 쉽게 설명하면 [a-Z0-9_]인 문자가 있는 곳과 아닌 문자가 있는 곳의 사이가 경계가 된다. \b는 문자열의 시작과 끝과도 매치가 되는데 만약 문자열의 시작과 끝이 \w가 아니라면 매치되지 않는다.
\B는 단어의 경계가 아닌 곳과 매치된다. 쉽게 말해 공백문자가 아닌 문자들 사이가 된다.
이 \b와 \B는 쉽게 와닿지 않을 수 있는데 아래 사이트에 입력해보면 시각적으로 경계를 보여주기 때문에 이해가 쉽다.
regex101: build, test, and debug regex
Regular expression tester with syntax highlighting, explanation, cheat sheet for PHP/PCRE, Python, GO, JavaScript, Java, C#/.NET, Rust.
regex101.com
I like listening to music을 소스로 입력해보고 \b와 \B를 입력해보았다.
분홍색 점선으로 표현된 부분이 바로 문자열의 시작과 끝 그리고 단어의 경계이다.
문자열이 \w가 아닌 다른 문자들, 위와 같이 "로 시작된다거나 .와 같이 점으로 끝날경우에는 문자열의 시작과 끝이 경계로 선택되지 않는다.
\B의 경우는 \b의 반대가 되는 곳들에 점선들이 위치한 것을 볼 수 있다. 두 \w 사이, 두\W 사이, 빈 문자열 그리고 \W로 문자열이 시작하거나 끝날경우 그 곳이 매치된다.
사례 1
소스 :
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
정규 표현식 : \b.
첫 번째 매치
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
전체 매치
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
\b.은 경계 다음에 오는 그 어떠한 문자든 선택되게 된다. 전체 매치에서 왜 공백들이 매치된 것인지 잘 이해가 되지 않을 수 있는데 경계들을 표시해놓은 아래 사진을 참고해보면 쉽게 이해가 될 것이다.
사례 2
소스 :
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
정규 표현식 : .\b
첫 번째 매치
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
전체 매치
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
.\b 는 단어 경계 앞에 있는 어떤 문자든 그 문자가 선택된다. 잘 이해가 안된다면 위 사진의 경계를 참고해보자.
사례 3
소스 :
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
정규 표현식 : \B.
첫 번째 매치
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
전체 매치
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
\B. 은 단어의 경계가 아닌 곳 뒤에 위치한 어떤 문자 하나와 매치된다. 아래 사진을 참고하면 이해가 쉬울것이다.
사례 4
소스 :
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
정규 표현식 : .\B
첫 번째 매치
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
전체 매치
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
.\B 는 단어의 경계가 아닌곳 앞에 위치한 어떤 문자 하나와 매치된다. 역시 위 사진을 참고하면 이해가 쉽다.
^와 *는 여러줄(multiline) 플래그를 켜지 않은 기본 상태에서는 소스가 여러줄일 경우에도 맨 처음과 맨 끝 부분 한 곳에만 매칭되지만 여러줄 플래그를 켜게 되면 각 줄의 시작과 끝에 매치되게 된다.
\A는 문자열의 시작과 매치된다는 점에서 ^와 유사하지만 여러줄일 경우 ^는 모든 줄의 시작 부분에 매치되지만 \A는 전체에서 맨 처음 시작과만 매치된다.
마찬가지로 \Z도 $와 유사하지만 \Z는 전체 문자열의 마지막과만 매치된다.
\A와 ^의 차이는 아래 두 사진을 참고하면 이해가 쉬울 것이다. \Z와 $역시 이와 똑같이 비슷하기 때문에 사진은 따로 첨부하지 않았다.
사례 1
소스 :
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
정규 표현식 : \A...
첫 번째 매치
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
전체 매치
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
여러줄 전체의 시작부분에 위치한 문자 3개가 매치된다.
사례 2
소스 :
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
정규 표현식 : ...\Z
첫 번째 매치
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
전체 매치
Ere iron was found or tree was hewn,
When young was mountain under moon;
Ere ring was made, or wrought was woe,
It walked the forests long ago.
여러줄 전체의 끝부분에 위치한 문자 3개가 매치된다.
1-3. 전방탐색, 후방탐색
전방탐색은 패턴이 일치하는지를 찾지만 그 값을 반환하지는 않는 패턴을 말한다.
(?=<검색할 패턴>) 이러한 형태로 사용되기 된다. 검색할 패턴에 들어간 것이 존재하는지 찾아보고 그것이 있어야 매치되지만 찾기만 할 뿐 그 값은 반환되지 않는다. 직접 예시를 살펴보면 이해가 쉽다.
사례 1
소스 : AAAX---aaax---111
정규 표현식 : \w+(?=X)
첫 번째 매치
AAAX---aaax---111
전체 매치
AAAX---aaax---111
\w가 1개 이상 그리고 그 뒤에 X가 오는지 찾아보게 된다. X가 반드시 있어야지만 매치되는데 그 매치에서 X는 빠지게 된다. 따라서 AAAX에서 AAA만 선택된 것을 볼 수 있다.
사례 2
소스 : AAAX---aaax---111
정규 표현식 : \w+
첫 번째 매치
AAAX---aaax---111
전체 매치
AAAX---aaax---111
\w가 1개 이상인 덩어리들이 모두 매치된 것을 볼 수 있다. 사례 1과 비교해보면 이해에 도움이 될 것이다.
사례 3
소스 : AAAX---aaax---111
정규 표현식 : \w+(?=\w)
첫 번째 매치
AAAX---aaax---111
전체 매치
AAAX---aaax---111
\w가 1개 이상인 덩어리들 뒤에 \w가 존재하는지 검사하지만 그것은 선택되지 않는다. 따라서 전체 매치를 보게되면 \w 덩어리들의 마지막 \w가 모두 선택되지 않았음을 볼 수 있다.
부정형 전방탐색은 전방탐색과 반대로 검색할 패턴이 존재하지 않아야 매치가 되며 역시 검색할 패턴은 포함되지 않는다.
(?!<검색할 패턴>) 이러한 문법으로 사용하며 사용법은 전방탐색과 동일하다.
사례 1
소스 :
Date: 4 Aug 3PM
정규 표현식 : \d+(?=PM)
첫 번째 매치
Date: 4 Aug 3PM
전체 매치
Date: 4 Aug 3PM
전방탐색이기 때문에 PM이 뒤에 오는 1개 이상의 숫자가 매치된다. PM은 선택되지 않는다.
사례 2
소스 : Date: 4 Aug 3PM
정규 표현식 : \d+(?!PM)
첫 번째 매치
Date: 4 Aug 3PM
전체 매치
Date: 4 Aug 3PM
부정형 전방탐색이기 때문에 PM이 뒤에 오지 않는 1개 이상의 숫자가 매치된다.
전방탐색은 일치하는 텍스트 다음에 무엇이 오는지 찾았다면 후방탐색은 일치할 텍스트 앞에 무엇이 오는지 찾는다.
(?<=<검색할 패턴>) 이런 문법으로 사용된다. 텍스트 앞에 검색할 패턴이 오면 매치되고 검색할 패턴은 선택에서 제외된다.
부정형 후방탐색은 텍스트 앞에 검색할 패턴이 오지 않아야 매치된다.
(?<! <검색할 패턴>) 이런 문법으로 사용된다.
사례 1
소스 :
Product Code: 1064 Price: $5
정규 표현식 : (?<=\$)\d+
첫 번째 매치
Product Code: 1064 Price: $5
전체 매치
Product Code: 1064 Price: $5
후방탐색이기 때문에 1개 이상의 숫자 앞에 $(\를 통해서 이스케이프 시켜줘야 함에 주의해야한다.)가 오는지를 검사하게 된다. 검색할 $는 선택되지 않는다.
사례 2
소스 :
Product Code: 1064 Price: $5
정규 표현식 : (?<!\$)\d+
첫 번째 매치
Product Code: 1064 Price: $5
전체 매치
Product Code: 1064 Price: $5
부정형 후방탐색이기 때문에 1개 이상의 숫자 앞에 $(\를 통해서 이스케이프 시켜줘야 함에 주의해야한다.)가 오지 않아야 한다.
여기까지 정리해놓은 내용만 잘 알아두어도, 어떤 정규표현식이 등장했을 때 어떤 의미를 가지는지 파악할 수 있을 것이다. 하나하나 익히는 것은 간단하지만 간단한 것들을 잘 조합해 정규식을 만드는 것은 쉽지않다. AI에게 물어보면 정규식을 꽤 정확하게 생성해주기 때문에 적극적으로 이용해보는 것이 좋다고 생각한다. 다만 직접 사용해보니 일부 정확하지 않은, 혹은 내가 요구하지 않은 내용까지 반영해서 정규식을 만들어주는 경우가 더러 있었다. 때문에 AI에게 맡겨서 생성한 정규식은 반드시 직접 하나하나 확인해봐야 하고 그러려면 위 내용들을 모두 잘 알고 있어야한다.
'기타' 카테고리의 다른 글
동기 / 비동기, 블로킹 / 논블로킹 (0) | 2025.01.09 |
---|---|
정규 표현식 (2) (0) | 2024.12.18 |
정규 표현식 (1) (0) | 2024.12.17 |