brunch

You can make anything
by writing

C.S.Lewis

by 웰콤반 Feb 24. 2017

재밌는
정규 표현식

손에 잡히는 정규 표현식을 읽고

 정규식에서 '*' 는 '모든 문자'를 의미한다. 이를 알면서도 cronjob 으로 find directoryname/* 하여 오래된 파일을 remove 하는 job을 걸어 놓고선, 지워지면 안되는 파일을 모두 지워버린 슬픈 기억이 있다. 이런 실수를 또 다시 하는 것을 방지하기 위하여, 얇아서 마음에 들었던 책 <손에 잡히는 정규 표현식 - Regular Expressions in 10 minutes> 내용을 브런치에 정리해본다. 정규 표현식으로 단어나 문장, 패턴을 매칭하는 일은 정말 재밌는 일이다. 


정규표현식

 정규 표현식(Regular Expression)은 줄여서 Regex, 정규식 이라고도 한다. 정규식은 일치 또는 패턴에 부합하는 문자를, 검색 또는 치환하기 위해 사용하는 '작은 언어 (mini ranguage)' 이다. 정규 표현식은 어떤 프로그램이나 유틸리티가 아니라 여러 개발 환경에서 문자열 조작을 위해서 사용 될 뿐이다.


문자 하나 찾기

 정규식을 사용하면 내가 원하는 패턴의 문자를 찾아낼 수 있다.

You can make everything by writing - C.S.Lewis

 정규식은 나열된 문자와 일치하는 문자를 찾아낸다. 예를 들어 정규식 'o' 에는 위 문구에서 'o'가 일치한다. 정규식 'can' 에는 위 문구에서 'can'이 일치한다. 기본적으로 가장 첫번째로 찾은 문자열을 반환하는데, 일치하는 배열을 반환 받고자 하면 /g/ (global) 전역 플래그를 사용하면 된다. 이런 플래그 값의 생김새는 프로그래밍 언어마다 다를 수 있다.

 정해진 문자 'o', 'can' 이 아닌 아무 문자를 찾으려면 어떻게 해야할까? 정규식에서 마침표(.)는 '아무 문자'를 의미한다. 빈칸이 될 수도 있고, 특수문자가 될 수도 있다. 마침표를 '아무 문자'가 아닌 정말 '마침표'로 사용하고 싶다면 역슬래시(\)를 사용한다. 정규식에서 특수문자 앞의 '\' 는 이스케이프 -문자 본연의 의미를 갖도록- 해준다. 따라서 위 문구에서 정규식 'c.n' 에는 'can' 이 일치, 'c\.n' 에는 일치하는 문자가 없게 된다.


문자 집합에서 찾기

대괄호([])는 문자 집합을 정의한다. 원소에 모두(AND) 일치가 아니라 한 문자라도 일치(OR) 하는 문자열을 찾는다.

하이픈(-)   '~부터 ~까지'의 범위를 나타내는 메타문자.

캐럿(^)  이 문자 바로 뒤의 문자나 범위를 제외하는 메타문자.

[abcde]  a 또는 b 또는 c 또는 d 또는 e == [a-e]

[a-z]  a 부터 z 까지의 문자 중 하나

[0-9] 0 부터 9 까지의 숫자 중 하나 

[A-Za-z0-9] A to Z, a to z, 0 to 9

[가-힣] 한글 전체

[가-하] 가갸거겨고교구규그기...각...나냐너녀...파퍄퍼펴...픽핀핃...핗...하

[^0-9] 숫자 제외

* 하이픈(-)은 대괄호([]) 안에서만 범위를 나타내는 메타 문자 역할을 한다. 그래서 마침표(.) 처럼 대괄호 밖에서는 이스케이프(\) 해 줄 필요가 없다.

* 한글 전체의 정규식은 a to z 처럼 유니코드상에서 한글의 첫번째인 '가' 부터 마지막인 '힣' 을 범위로 지정한다.


메타 문자 사용하기

정규식에는 마침표가 '아무 문자'를 의미하고, 역슬래시는 '문자 본연의 의미'로 이스케이프 해주는 것 처럼 다양한 메타문자들이 있다. 책에 나왔거나 자주 사용했던 메타문자만 나열해보면 아래와 같다.

\n  new line, 줄바꿈

\t  tab

\s  white space (모든 공백 문자)

\d 숫자 == [0-9]

\D 숫자가 아닌 문자 == [^0-9]

\w  == [0-9a-zA-Z_]

\W  == [^0-9a-zA-Z_]



반복 찾기 

지금까지의 정규식 패턴은 한 글자에 부합한다. 'abc' 에 완벽하게 부합하는 정규식 패턴은 '\w' 가 아니라 '\w\w\w' 인 것이다. 이렇게 글자 n개에 부합하는 반복되는 패턴을 위해서 정규식에서는 '몇 번' 에 해당하는 메타문자도 제공한다.

+   하나 이상 일치 (최소한 하나, 없으면 일치하지 않는다)

  ex) wel@come.ban 에 완벽히 일치하려면

   - 반복 메타 문자 사용하지 않는 경우 : \w\w\w@\w\w\w\w\.\w\w\w

   - 반복 메타 문자 사용 : \w+@\w+\.\w+

*   없거나 하나 이상 일치

?   없거나 하나 일치

  ex)  https?:// 는 http://  https:// 둘 다 일치한다. 메타문자 물음표는 바로 앞의 's' 가 없거나 하나 일 때 일치하기 때문이다.

{숫자}   문자가 정확히 '숫자' 개 일치

 ex) #[0-9A-Za-z]{6}  :  #F3F3F3 과 일치한다. #FFF 는 일치하지 않는다.

{최솟값, 최댓값}  문자가 일치해야 하는 최솟값과 최댓값

 ex) #[0-9A-Za-z]{3,6} :  #F3F3F3 과 일치한다. #FFF 와도 일치한다.

{최솟값,}  문자가 일치해야 하는 최솟값

 ex)  #[0-9A-Za-z]{6,} :  #F3F3F3 과 일치한다. #FFF 는 일치하지 않는다.

게으른(lazy) 수량자  

*?  

+?

{n,}?

기존 수량 메타문자에 ? 를 붙이면 게으른 수량자가 되는데, 다음과 같은 상황을 방지한다.

아래 문장에서 bold 된 문자만 뽑고 싶을 때,

my <b>name</b is <b>welcome.ban!</b>

 탐욕적 수량자 : <[Bb]>.*</Bb>  

 -  모든 문자 (.) 가 없거나 하나 이상 (*) 일치하는 조건 이기 때문에 원하지 않는 'is' 문구도 일치하게 된다.

 게으른 수량자 : <[Bb]>.*?</Bb>  

 -  모든 문자 (.) 가 없거나 하나 이상 (*) 인 것이 최대 하나 (?) 일치하는 조건 이기 때문에 'is' 는 부합하지 않고 태그만 일치하게 된다.



위치 찾기

정규표현식 cat 에는 cat도 부합하고 scattered 도 부합한다. 이번 장에서 cat 으로 시작 하는 단어 등등 단어의 위치도 지정하여 정규식으로 표현할 수 있다.

\b  단어 경계  : 단어의 시작이나 끝

ex)  cat  scattered  catch

- \bcat  :  단어의 시작이 cat 인 단어,  cat, catch 가 일치한다.

- cat\b : 단어의 끝이 cat 인 단어, 일치하는 단어가 없다.

- \bcat\b :  단어의 시작과 끝이 cat인 단어,  cat 이 일치한다.

\B \b의 반대



하위 표현식 사용하기 

반복찾기에서 패턴의 반복을 나타내는 메타문자 ?, * 등은 바로 앞 문자의 반복 횟수만을 표현한다. 따라서 공백 nbsp; 을 여러 칸 찾아내고 싶을 때, nbsp;* 으로 정규식을 작성하면 nbsp;;;; 는 해당 될 수 있겠지만 공백을 여러 개 찾아내지 못한다. 이럴 때 하위표현식을 사용한다. 하위표현식은 괄호로 표현식을 묶어서 한 항목으로 다룬다. 

 예를 들어, 지역번호를 포함하는 전화번호를 정규식으로 표현하고 싶을 때

02|031|051-\d{3,}-\d{4} 으로 정규식을 작성한다면, 02-123-1234 는 불일치, 051-123-1234 는 일치하게 된다. 메타문자 | 는 'or' 의 의미를 가지는데, 바로 앞 뒤의 문자만 살펴본다.

그래서 이 정규식의 의미는 02 or 031 or 051-\d{3,}-\d{4} 이 된다. 하위식으로 묶으면 문제가 해결된다.

(02|031|051)-\d{3,}-\d{4} 하위식-괄호-으로 묶인 문자 중 하나를 일치시키려 한다는 의도를 명시적으로 표현하는 것이다.






regex test site : 여러 메타 문자를 직접 매칭 시키면서 적용해보면 재미있다.

regex test site2 : 여기도 재미나다.

http://www.regexplanet.com/  : 여기도 재미나다.

http://www.regexplanet.com/advanced/java/index.html java regex test 


브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari