정규식 (Regular Expression) 2) 사용용법

글쓴이 Engineer Myoa 날짜

직전 글 “정규식 (Regular Expression) 1) 기본문법” ( https://myoaftp.duckdns.org/techlog/archives/356 )

에 이어 문법을 하나씩 풀어 실제로 사용되는 용법에 대해 확인해보도록 하겠습니다.

아래 글은 제가 약 2년전 작성했던 글로 두서없이 나열한 설명이라 조금 부족하지만 레퍼런스로 활용하기 좋을 것 같아 그대로 복사해보았습니다.

한창 갓 배웠을 때라 초심의 마음이 담겨있지만서도

어설픈 표현이 많고 내용의 진행도 많이 미숙함을 감수해야 할 것 같습니다.

 

정규식 Regular Expression 기초 1/3

 

http://zvon.org/comp/r/tut-Regexp.html에 기반하여 설명합니다.

정규식 테스트는 http://regexr.com 을 이용하시기 바랍니다.

 

여타 언어나 이론들을 배우기 방법으로, 저는 2가지 플랜을 사용합니다.

 

하나는 수많은 예제를 보면서 메커니즘을 이해하고 잘 정돈된 문서를 보는것과,

다른 하나는 처음부터 문서를 정독하면서 마지막 장까지 나아가는 방법입니다.

 

콕 집어 어떤게 더 좋다 라고는 말할 수 없겠지만 정규식같이 사용되는 기호들이 생소한 경우에는 전자를 이용한 방법이 더 좋았습니다.

설명을 진행하는동안, 위에 사이트에 나와있는 예제들을 전부 풀어쓰고 후에 연산자들에 대해 기술하도록 하겠습니다.

 

기본적으로 식은 /“정규식표현”/g 이며 특수한 상황에서 //i //gi //gim 등에 대해 사용방법도 끝에 설명하겠습니다.

첨언으로 vim에서 /(슬래시)를 입력함으로써 //g의 형태를 사용하겠다는 의미에서 검색하는 핫키가 되겠습니다.

 

 

1. 

 

정규식은 기본적으로 case sensitive(대소문자 구별)합니다. 그 말은 hello와 Hello가 서로 다른 식이라는 것을 의미합니다.

“Hello, world” 라는 문장에서 Hello라는 식으로 검색했을 때는 “Hello, world” 부분이 매치가 되네요. 하지만 hello라는 식으로 검색했을 때는 어느 부분도 매치되지 않습니다.

 

다시 한 번 강조하지만 정규식의 Default 값에서는 대소문자를 구분합니다.

 

2.

정규식에서는 모든 문자를 패턴을 위한 문자로 인식합니다. 무슨말인고 하면 “ ” 와 “  ”는 다르고 “.” 과 “..”는 다르다는 말이죠. 공백, 탭, 개행 전부다 이스케이핑(추후 나옴)없이는 전부 단일문자로 인식합니다.

위에 케이스에서도 “Hello, world!”를 Hello, world로 검색하면 “Hello, world!”가 매치 되지만

Hello,  world를 검색했을경우에는 아무것도 매치가 되지않습니다.

 

3. 

본격적으로 정규식 기호들에 대해 나오기 시작합니다.

^과 $는 각각 문장의 첫, 끝을 의미합니다.

“사과는 사과” 라는 문장에서

 

^사과 로 검색 시 “사과는 사과”

사과$ 로 검색 시 “사과는 사과

가 매치됩니다.

 

당연히 사과^ 와 $사과 는 컴파일 에러는 나지 않지만 실행중 논리에러가 나게되죠.

(문장에 시작앞에 다른 문자가 존재할 수 없으며, 문장에 끝뒤에 다른 문자가 존재할 수 없죠)

 

그냥 사과 로 검색하면 “사과는 사과”가 매치되며 파이썬 정규식 모듈에서는 이를 list의 형태로  [“사과”, “사과”]를 반환합니다.

 

 

4.

앞서 ^과 $는 각각 문장의 처음, 끝을 나타낸다고 말씀드렸습니다.

그런데 실제로 ^이나 $라는 문자가 필요할 땐 어떻게 할까요?

바로 이때 이스케이핑을 하게됩니다.

\(백슬래쉬)를 사용하려는 기호나 문자앞에 배치하면 그 기능이 이스케이핑되어(escape. 키보드의 esc가 escape) 새로운 기능으로 작동하게됩니다.

 

바로 \^, \$ 처럼요.

 

위에 예제 자체는 훌륭하나 배우는 입장에서 이해하기 난해한 예제입니다.

예제를 살짝 수정해보겠습니다.

 

^^ 오늘도 좋은하루입니다.~^^!

 

이 문장에서 ^^를 찾으려면 어떻게 할까요?

\^\^로 검색하면되겠죠.

 

^^ 오늘도 좋은하루입니다.~^^!” 2개가 매칭됐네요.

오늘따라, 에있는 ^^만 찾고 싶습니다.

 

^\^\^로 검색해보겠습니다.

^^ 오늘도 좋은하루입니다.~^^!”

정확하게 원하는 결과가 나왔습니다.

 

$의 경우도 같습니다. $문자 자체를 사용하려면 \$.

$라는 문장맨끝을 의미하는 기호로 사용하려면 $로 사용하시면됩니다.

 

만약 보기가 불편하다고 ^ \^\^ 와 같이 식을 정의하면 아무것도 검색이 되지않습니다.

이것은 마치

테스트\n 과 테스트 \n이

“테스트”

“테스트 ”처럼 둘은 엄연히 다른 문자열 리터럴을 의미하기 때문에 보기 불편하더라도 익숙해지도록 노력해야합니다.

 

5.

“.” 은 any character. 즉 아무개 문자를 의미합니다.

.에는 거의 대부분이 해당됩니다. 영소대문자, 숫자, 한글, 특수문자, 공백 등..

하지만 포함이 안되는 것이 있죠. 바로 new line(개행문자. 즉, 엔터로 개행한)입니다. new line을 포함해서 찾는방법은 따로 있는데 지금은 설명할 시점이 아닌 것 같습니다.

 

예방주사겸 맛보기로만 보여드리자면

[\w\W] 또는 [\s\S] 등으로 정의할 수 있습니다.

부울대수에서 A + A’ = 1 이라는 보원법칙을 생각하시면 되겠습니다.

 

Case2에서 …… (점 6개)를 검색하는데 왜 powerf까지만 검색이될까요?

이유는 ul!!!의 길이가 5개이기 때문입니다.

쉽게 풀어쓰자면 Case2에서 매치되는 그룹은

[“Regula”, “r expr”, “ession”, “s are ”, “powerf”]입니다. 전부 6글자씩인데 ul!!!는 5글자이기 때문에 식에 부합하지않습니다.

뒤에 !가 하나 더 추가된다면 매치가 되겠죠.

 

/……/g

Regular expressions are powerful!!!!

>>> [“Regula”, “r expr”, “ession”, “s are ”, “powerf”, “ul!!!!”]

 

6.

5에서 “.”역시 일반적인 문자로 사용하는게 아닌 하나의 식으로 사용했었습니다.

그렇다면 정말로 .을 찾고싶다면 어떻게 할까요?

4에서 배웠던데로 이스케이핑(escape)이 필요합니다.

그저 \. 만 해주면 되는거에요.

. 으로 검색시에는 [“O”, “.”, “K”, “.”] 총 4개가 매치되는군요.

\.로 검색시에는 [“.”, “.”] 총 2개가 매치됩니다. 우리가 원하는 결과네요.

 

특정문자(아무개문자)와 .을 같이 찾고싶다,

.\. 식을 사용하면됩니다.

.과 특정문자를 찾고싶다면

\.. 이 되겠죠?

 

 

7.

[ ]는 문자의 집합을 나타냅니다. [ ]안에는 문자가 들어갈수도, 문자셋(set)이 들어갈수도, against식이 들어갈수도 있습니다.

 

배우기전에 앞서 아래와 같은 룰이 존재하므로 익히고 넘어갑시다.

– : 문자의 범위를 의미합니다.

[ㄱ-ㅎ가-힣]은 한글전체를 의미합니다.

[a-z]는 영소문자의 범위를 의미합니다.

[A-Za-z]와 같이 영문자 전부를 포함할 수도 있으며,

[0-9]처럼 숫자만을 포함할 수도 있습니다.

[ㄱ-ㅎ가-힣0-9]처럼 여러개의 문자집합을 섞어서 사용할 수도 있습니다.

 

: 문자집합을 부정합니다. 다시말해 문자 집합내의 문자를 걸러서 매치합니다.

[^a-z]는 a부터 z까지의 범위를 검색하지않습니다.

[^ 0-9]는 0부터 9까지 그리고 공백을 검색하지 않습니다.

[^ A-Za-z0-9]와 같이 여러 집합을 섞어서 사용할 수도 있습니다.

 

 

이제 위에 식을 보면

How do you do?에서 [oyu]를 검색하면

[“o”, “o”, “y”, “o”, “u”, “o”] 만 매치가됩니다.

말 그대로 o,y,u를 하나의 문자집합으로 두고 이중에 하나라도 들어가면 매치하는거죠.

 

[dH]. 처럼 대소문자도 구문합니다.

 

[가나라][방면]

“가방안에 나비가 들어왔노라면.”

이라는 문장에서 위와 같은 식으로 검색을하면

[“가방”, “나비”, “라면”] 이 매치가 되는것이죠.

이는 가방, 가면, 나방, 나면, 라방, 라면 의 경우를 검색하는 식이 의미합니다.

 

8.

위에서 짚고 넘어간 것처럼 –은 문자의 범위를 지정합니다.

즉 [C-K]는 [CDEFGHIJK]와 동일하고 [2-6]은 [23456]과 동일하단 의미이죠.

 

9.

에제 7과 마찬가지로 위에서 ^는 문자집합을 부정하는 식이라고 언급했습니다.

예제를 보면 [^CDghi45]는 C, D g, h, i, 4, 5를 제외하고 검색한다는 뜻입니다.

[^W-Z]처럼 범위를 부정하는 방법도 있습니다.

 

추후에 배우겠지만 정규식은 \s \w \S \W \d \b처럼 자주 사용되는 문자집합을 사전에 정의해두고 사용할 수 있도록 만들어져있습니다. 매우 강력한 힘을가진 식입니다.

 

2부에서 뵙겠습니다.

 

정규식 Regular Expression 기초 2/3

 

문자집합까지 끝을 냈고 이번에는 OR연산 그리고 수량자(*, ?, +)에 대해 알아보겠습니다.

 

10. 

소괄호안에 |(Shift + \키) 를 넣으면 정규식에서의 OR연산이 됩니다.

“월요일 화요일 수요일 목요일 금요일 토요일 일요일”에서

(|)요일 로 검색하면 [“토요일”, “일요일”]이 매칭됩니다.

 

11. 

수량자에 들어가기 앞서 수량자는 크게 *, +, ? 3로 나눌 수 있습니다.

*는 없거나 무한에 가까울때까지 검색,

+는 무조건 1개이상 이며 무한에 가까울때까지 검색,

?는 앞의 문자가 있거나 없거나 (한글자만) 검색을 하게 됩니다.

 

쉽게 정리하자면

*는 앞문자를 x번 검색합니다. ( 0 <= x )

+는 앞문자를 x번 검색합니다. ( 1 <= x )

?는 앞문자를 x번 검색합니다. ( 0 <= x <= 1 )

 

12. 

수량자 *에 대한 예들입니다.

아무개문자 . 와 수량자 *가 만나

문장전체가 하나의 매치로 발견되었습니다.

 

 

13. 

수량자 +에 대한 예들입니다.

수량자 +를 이해하기에 적절한 예시가 없어보여 새로운 예시를 들어보겠습니다.

“나는 사과를 2개 먹었다.” 에서

[0-9]+개 먹었다. 라는 식으로 검색하면

[“2개 먹었다.”] 가 검색됩니다.

 

 

“나는 사과를 15개 먹었다.” 많이도 먹었군요.

이 문장에서 같은 [0-9]+개 먹었다. 식으로 검색하면

[“15개 먹었다.”] 가 검색됩니다.

하지만

“나는 사과를 one개 먹었다.” 라는 식에서

[0-9]+개 먹었다. 식으로 검색하면

아무것도 발견되지 않습니다.

왜냐하면 “개 먹었다” 앞에 숫자가 1개 이상 오라고 식을 작성했기 때문이죠.

따라서 +는 최소한 해당 문자를 1개 이상 포함해야만 검색이됩니다.

 

14.

수량자 ?에 대한 예들입니다. 아까보다 더 적절하지 못하네요

마찬가지로 새로운 예시를 들어보겠습니다.

 

“게임을 하고싶다” 라는 문장과

“게임을 더 하고싶다” 라는 문장 2개가 있습니다.

 

어떻게 하면 두 문장 다 매치가 될까요?

 

“더? ”를 ?연산자로 넣으면됩니다. 물론 눈치가 빠르신 분들은 알아차리셨겠지만 *로 동작합니다.

 

게임을 더? ?하고싶다 라는 식은 분명히라는게 들어갔지만 두 문장다 이상없이 매치가 됩니다.

바로 수량자 ? 덕분에 “더”라는 글자가 들어가도 되고, 들어가지 않아도 되기 때문입니다.

여기서 한가지 보기 싫은부분은 “더? ?”죠. 우리는 더 ?를 원했지만 정규식을 이를 허가하지 않습니다.

따로따로 더가 있거나 없고, 공백이 있거나 없거나로 식을줘야만이 위 문장에서 정상적으로 검색이 가능합니다.

 

이에 대해 추후 나올 subexpression(하위식)에 해답이 있는데

( )?라고 식을주면? ?와 같은 동작을 하고 이에 조금나아가( ?)?로 작성을 한다면

“게임을 하고싶다”

“게임을 더하고싶다”

“게임을 더 하고싶다”

모두 매치가 됩니다 🙂

 

 

http://myoa.kro.kr/라는 주소 문자열에서

https?:\/+w*\.?myoa\.kro\.kr 라는식으로 검색해봅시다.

하나씩 분석해보자면(보기좋게 자르자면)

http s? \/+ w*\.? myoa\.kro\.kr 입니다.

 

http : 말 그대로 http를 검색합니다.

s? : s 한글자가 있거나 없거나(1개이거나 0개)를 검색합니다.

\/+ : \/(/를 이스케이핑한 것)가 1개이상을 검색합니다.

w*\.? : w가 없거나 또는 여러개거나 그리고 “.”이 있거나 없거나를 검색합니다.

myoa\.kro\.kr : 그리고 마지막으로 메인주소인 “myoa.kro.kr”를 검색합니다.

 

이 정규식이 찾아 낼 수 있는 주소는 아래와 같습니다.

http://myoa.kro.kr

https://myoa.kro.kr

http://www.myoa.kro.kr

https://www.myoa.kro.kr

 

갑자기 장황한 식이 나와서 당황할 수 있으나 하나씩 차근차근 곱씹어 보시고, 모르는 것은 질문바랍니다.

 

15.

다음은 지정 수량자입니다. 사실 지정이라고 부르지는 않지만 의미상 편하게 부르기 위해 지정해봤습니다.

해선 안될 짓중 하나이긴 한데.. 너무 모호해서

 

수량자 ?는 너무적고 수량자 *는 너무 많다. 싶으면 브레이스( { } )를 이용합니다.

이는 수량을 직접 조절할 수 있으며 가독성에 좀 더 도움이 될 수도 있죠.

 

사용식은 {x,y}이며 x > y여야 합니다. 강력한 주의사항은 절대로절대로 {}안에 공백을 넣어서는 안됩니다.

또한 x나 y를 생략가능하며 문자 하나를 생략하여 단항일 경우 0은 제외하고 사용해야합니다. (infinity loop에 걸림)

{1} : 1개

{2,6} : 2개 이상 6개이하

{5,} : 5개 이상

{,6} : 6개 이하

 

가장 간단하게 .{5} 라는 식은 아무 문자나 5개를 찾는다 입니다.

따라서 [“One r”]이 첫 번째로 매치가 됐고 그 뒤를 이어서 [“ing t”, “o bri”…….]가 매치가 됩니다.

[els]{1,3} 식은 “e”, “l”, “s”중에 1~3번 반복된 부분을 찾는다 입니다.

그래서 e도 찾아지고 ll, ess가 찾아지는겁니다.

 

간단하죠?

 

16.

이번에는 수량자 *, +, ?와 수량자 { }의 상관관계를 배워보겠습니다.

 

15번을 잘 보신분이라면 각 수량자를 수량자{ }로 표현이 가능하다는 것을 눈치챘을텐데요,

 

* == {0,} #단항이 아니라 0이 올 수 있습니다.

+ == {1,}

? == {0,1}

 

위에 예시 또한 같은 의미를 담고있습니다.

하지만 보통의 경우 가독성을 위해 수량자 *, +, ?를 주로사용하며 특정 개수일때만 수량자 {}로 지정해서 사용한답니다.

 

17. 

이번에는 수량자의 특별기능입니다.

 

“하늘과 땅과 바람과 물과” 라는 문장에서

~~과 들을 추출하려고 합니다.

지금까지 배운바로는 .+ 또는 .*(추천하지 않음)를 사용할텐데

그렇게 호락호락하게 원하는 결과를 내어주지 않습니다.

왜냐하면 위에 식의 결과는 다음과 같기 때문입니다.

[“하늘과 땅과 바람과 물과”]

왜 그럴까요?

 

정규식 수량자에는 크게 탐욕적 수량자(Greedy quantifier)와 게으른 수량자(Lazy quantifier)로 나뉩니다.

기본적으로 수량자를 사용할때는 탐욕적 수량자로 동작합니다. 하지만 수량자 뒤에 ?를 붙이면 게으른 수량자로 바뀌어 동작합니다.

탐욕적 수량자 : 최대한 넓은 범위를 매치시키려고 합니다.

게으른 수량자 : 최대한 좁은 범위를 매치시키려고 합니다.

 

.+?를 사용해볼까요?

[하늘과”, “땅과”, “바람과”, “물과]

 

하나씩 차근차근 생각해보죠.

.+

.는 아무 문자를 의미합니다.

맨처음가 매치되겠죠? 거기서부터 +  1개이상의 아무문자를 잡습니다.

언제까지 로 끝날때까지

 

늘과 땅과 바람과 물

 

합쳐서 [“하늘과 땅과 바람과 물과]가 매치됩니다.

한 마디로 가장 크게잡는거죠 .+ 의 범위를

 

하지만 .+?는 아까 말한것처럼 가장 좁은 범위를 매치시키려고 합니다.

.는 아무 문자를 의미합니다.

역시 맨처음 “하”가 매치됩니다. 거기서부터 +. 1개 이상의 아무문자를 잡습니다.

가 나올때까지

 

중요한부분은 나올때까지입니다.

 

——

——

…..

 

합쳐서 [하늘과”, “땅과”, “바람과”, “물과] 4개의 그룹으로 매치됩니다.

 

 

그렇다면

r.?? 식은 어떻게 해석될까요?

r 그리고 아무문자(.)인데 있어도 되고 없어도(0 or 1) 됩니다. 근데 최소로(?) 잡겠답니다.

당연히 최소로 잡으려면 아무문자가 0개여야하겠죠?

그래서 결과적으로 이식은 r 단일문자만 매치하게됩니다.

 

 

 

 

마지막 탐욕적 수량자랑 게으른 수량자를 너무 장황하게 설명했는데 수량자는 잘못이해하고 잘못사용하면 infinity loop에 빠지는건 둘째문제이고 논리적 오류가 어디서 발생했는지 못찾아서 골때리는 경우가 허다합니다.

따라서 수량자를 적절하고 잘 사용하고 다음에 배울 하위식(subexpression)과 적절히 조합한다면 자신에게 필요한 정규식이 완성될 것입니다.

 

기초 2/3편을 마치겠습니다. 수고하셨습니다.

 

 

정규식 Regular Expression 기초 3/3

 

지금까지 기본적인 아무개문자, 문자집합, 연산자, 수량자를 배웠습니다.

이번 강의를 끝으로 사전정의된 문자집합, 하위식과 하위식보조표현,

그리고 부록으로 정규식의 플래그에 대해서 알아보도록 하겠습니다.

아래 나올 사전정의된 문자집합들은 반드시 외우시기 바랍니다. 외워야만 하는 부분입니다.

 

 

18.

\w는 문자“w”를 이스케이핑하여 “w”가 아닌 [A-Za-z0-9_]를 의미합니다.

당연하게도 이 문자집합에 대해서도 수량자를 적용할 수 있습니다.

 

19.

반대로 \W \w를 제외한 모든 문자에 해당됩니다.

\w [a-zA-Z0-9_] 라면 \W [^a-zA-Z0-9_]입니다.

따라서 영소대문자, 숫자, 언더스코어( “_” )를 제외하고 찾게됩니다.

 

 

20.

\s“s”를 이스케이핑하여 공백 문자를 찾게해줍니다. 여기서 공백은 “ ”만 의미하는 것이 아니라 “\n” 뉴라인도 포함합니다. 당연히 “\t” 탭도 공백이므로 탭문자도 포함합니다.

반대로 \S는 공백을 제외한 모든 문자를 찾습니다.

 

 

21.

\d는 Numeric을 찾습니다. 문자집합으로 표현하면 [0-9]입니다.

\D는 Numeric을 제외한 문자를 찾습니다. 문자집합으로 표현하면 [^0-9]입니다.

 

 

22.

 

\b는 문자의 경계선을 찾습니다. 이해하기 약간 모호할 수 있습니다.

 The best plan is no plan.

이해를 돕기위해 음영처리했습니다.

\b를 검색해볼까요?

이런, Infinite Exception이 발생합니다. 이는 \b단일 식이 순환참조를 유발시키기 때문입니다.

어디 단어에서부터의 경계인지가 모호하기 때문에 정확한 판단을 내릴 수 없고 무한루프에 빠지게 되죠.

\b.+\b 식으로 검색해보겠습니다.

[“The”, “ ”, “best”, “ ”, “plan”, “ ”, “is”, “ ”, “no”, “ ”, “plan”] 이 매치됩니다.

 

“ The”에서 단어의 경계는 “ ”도 아니고 “T”도 아닙니다. 그 사이가 경계죠. 굳이 표현하자면 “ |T” 저 부분이 됩니다.

따라서 \b는 저 경계를 찾는 것입니다.

\b.+\b 식은 경계와 하나이상의 아무문자와 경계를 찾습니다.

저번에 제가 .은 공백(“ ”)도 찾는다고 말씀드렸습니다.

그래서 “ ”도 매치가 되는겁니다.

“The| |best”

“best| |plan” 이 부분도 식에 부합하기 때문이죠.

 

 23.

\B는 \b의 반대를 찾습니다. 따라서 단어와 단어사이의 경계가 아닌부분 즉 문자와 문자사이의 경계를 찾습니다.

“The best plan is no plan”라는 문장에서는

“T|h|e b|e|s|t p|l|a|n i|s n|o p|l|a|n”

\B.\B 식은

[“h”, “e”, “s”, “l”, “a”, “l”, “a”] 만 매치될겁니다.

is no에서 i와 s사이는 분명 \B가 맞습니다. 하지만 o뒤는 문자와 문자사이의 경계가아니라 단어와 단어사이의 경계가 되죠. 따라서 식에 부합하지 않습니다.

 

실제로도 다음과같이 매치됩니다.

 

 

24.

24번은 통용되는 정규식이 아니기 때문에 제외하겠습니다.

 

 

 

25. 26.

 

 

25번을 진행하기전에 하위식과 그 연산들에 대해 알아보겠습니다. 여기서부터는 굉장히 고차원적인 내용이 나옵니다.

여러본 곱씹어보면서 읽어보세요.

 

하위식은 정말 간단합니다. 괄호안에 식을 넣어주면됩니다. /(이렇게요)/g

이제 매치와 그룹의 차이점을 알려드릴텐데

서브넷마스크 B클래스에 해당하는 “255.255.0.0”를 가지고 지지고 볶아보겠습니다.

각 옥텟에 해당하는 숫자만 가져오는걸 목표로 하겠습니다. (우리는 IPv4의 주소형식에 일치하는지를 보는 것이 아니라 정상적인 IP주소를 기준으로 각 옥텟의 숫자를 가져오는 것이 목표입니다)

우리가 배운바로는 저 IP주소를 정규식으로 잡아보기위해

\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} 로 작성하게됩니다.

[“255.255.0.0”] 이 잡히죠.

하지만 우리가 원하는건 각 옥텟의 숫자입니다.

이럴경우에는 subexpression을 이용해서 식은 전체를 매치시키되, 원하는 값만 그룹화합니다.

 

(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}) 식을 이용하면

[“255.255.0.0”] 이 매치되고

[“255”, “255”, “0”, “0”] 로 그룹화됩니다.

매치는 말 그대로 식전체에 부합하는 매치결과를 반환하고, 그룹은 하위식이 있을 경우 하위식의 내용들만 추출해서 그룹화하여 반환합니다.

 

하지만 하위식을 사용하다보면 몇몇 문제를 마주칩니다. 자주 사용되어지는 상황들에 대해 기술해보겠습니다.

 

1) ?:

OR연산을 예시로들자면

“The chair is under the desk.” 라는 문장에서 의자가 어디에 있는지를 찾아내려고 합니다.

(on|in|under).+ 의 식을 이용하고자 합니다.

[“under the desk”] 가 매치되고 [“under”] 가 그룹으로 반환됩니다.

우리는 의자가 어디에 있는지를 알고싶은것이지, 굳이 전치사를 그룹으로 얻고 싶지 않습니다.

이럴 때 하위식 맨앞에 “?:”를 넣어줍니다.

(?:on|in|under).+

이 경우 [“under the desk”] 가 매치되고 그룹되는 것은 없습니다.

 

2) ?=

전위연산의 긍정형입니다.

전위연산이란, 전위연산식 앞에 일치하는 패턴을 찾는것으로써

위 예시를 보면

\w+(?=X) 라는 식으로 [“AAA”]가 매치되었습니다.

“AAAX—AXXAAA-AbcdxX” 라는 문장에서는

[“AAA”, “AX”, “Abcdx”] 가 매치됩니다. 3개의 요소 전부 뒤에 “X”가 붙는다는 공통점이있죠.

하지만 매치되지는않습니다.

이러한 경우를 단순히 Non-Capturing이 아니라, Consume하지 않는다고 합니다.

저도 정확하게 이해한 개념이 아니기 때문에 섣불리 단정지을 수는 없지만 위에 \b처럼 해당 문자를 캡쳐하지않고 경계를 나타낸다고 보는게 좋습니다.

AAA|다음과 같이요.

(\w+)X 와는 다른 결과죠. AAAX까지 매치가 되고, AAA가 그룹으로 반환됩니다. X를 소비한셈이 되죠.

 

 

3) ?!

전위연산의 부정형

?= 전위연산의 부정형입니다.

위에서는 해당 식이 있으면 검색이지만 부정형은 없어야만 가능합니다.

그래서 단일 문자보다는 문자집합이나 OR연산을 통해 필터링처럼 사용됩니다.

 

4) ?<=

후위연산의 긍정형

전위연산이 Capture(lookahead)였다면

후위연산은 

(lookabehind)Capture입니다.

따라서 (?<=X)\w+

“XAAA—BXADEF—POWERX” 라는 문장에서

[“AAA”, “ADEF”]가 매치됩니다.

주의할점은 위에도 적었듯이, 후위연산식 뒤에 캡쳐할 식을 작성하셔야합니다.

 

5) ?<!

후위연산의 부정형

후위연산역시 부정형이 존재합니다.

작동은 방식은 전위연산의 부정형과 같습니다.

 

※ 단, 후위연산은 JS에서 공식적으로 지원하지않습니다.

PCRE 표준을 따르는 regex 모듈에서는 지원을 합니다.

 

 

정규식 플래그 (Regular Expression Flags)

(http://regexr.com 에서 발췌)

 

I

Makes the whole expression case-insensitive. For example, /aBc/i would match AbC.

1강에서 배웠듯이 정규식은 기본적으로 case sensitive(대소문자 구별)합니다. 하지만 i플래그를 주면 case-insensitive되어 대소문자구별없이 검색하게됩니다.

ex)“Power! power! POWER!”라는 문장에서

/power/g

>> [“power”]

/poWER/gi

>> [“Power”, “power”, “POWER”]

 

g

Retain the index of the last match, allowing subsequent searches to start from the end of the previous match.

Without the global flag, subsequent searches will return the same match.

 

RegExr only searches for a single match when the global flag is disabled to avoid infinite match errors.

 

마지막 매치가 끝날때까지 계속 해서 검색을합니다. g플래그가 없을경우에는 한번이라도 매치되는 결과가 나온다면 검색이 종료됩니다.

ex) “과일은 우리에게 많은 영양소를 제공합니다. 과일섭취를 늘립시다.”라는 문장에서

/과일.+/g

>> [“과일은”, “과일섭취를”]

/과일.+/

>> [“과일은”]

 

 

m

When the multiline flag is enabled, beginning and end anchors (^ and $) will match the start and end of a line, instead of the start and end of the whole string.

Note that patterns such as /^[\s\S]+$/m may return matches that span multiple lines because e the anchors will match the start/end of any line.

^ $는 “첫”문장의 시작부터 “마지막”문장의 끝까지를 판단합니다. 하지만 m 플래그를 사용한다면 그 문장의 범위가 각 문장을 좁혀져 판단합니다.

 

ex) 

 

 

/^[\w\W]+?$/g 식은 전체를 한문장으로 판단하여 전체가 매치되는 반면,

/^[\w\W]$+?/gm 식은 각 문장의 처음과 끝사이의 모든([\w\W]+?)문자를 가져오라는 의미이므로

각 문장, 즉 총 11줄을 매치하고 그룹화합니다.

 

 

이렇게 지금까지 3장에 걸쳐서 정규식 Regular Expression의 기초를 배워봤습니다.

 

수고많으셨습니다.

 

출처: [사진찍는 서버엔지니어]

 

 

참고문헌

http://zvon.org/comp/r/tut-Regexp.html


5개의 댓글

답글 남기기

Avatar placeholder

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다