반응형
04-reg

 

정규 표현식은 특정 데이터를 추출하는데 아주 유용하다. 대량의 문서에서 원하는 데이터를 찾을때 정규 표현식 만한 게 있을까?

하지만 정규 표현식은 처음 배우기 까다롭고, 배웠어도 안 쓰다보면 쉽게 까먹는다.

이번 글을 통해 정규표현식에 대해 공부하고, 자주 쓰는 표현을 정리해보고자 한다.

정규표현식을 시작하거나, 관련 예제 (튜토리얼)를 찾고 있다면 도움이 될 글이다.

 

이번 글에서는 다음과 같은 내용을 다룬다.

  • 정규표현식 기본 원리
  • 정규표현식 기본 표현들 ( {n,m} , [a-zA-Z], [ㄱ-ㅎㅏ-ㅣ] , ()(), ^abc )
  • 자주 쓰는 표현들 (이메일 추출, 전화번호 매칭, 한글 제거, 특수문자 제거 등)

 

그럼 시작해보자

 

1. 정규 표현식이란?

정규표현식은 특정한 규칙을 찾는데 쓰인다. 예컨데 한글로된 문서에서 영어 알파벳을 없애고 싶다거나, 이메일만 찾고 싶다거나 할때 쓰인다.

 

예컨데 '안녕하세요 abc 좋은날이네요' 라는 문자열에서 abc만 찾고 싶다고 해보자.

파이썬 함수를 사용할 경우에는 abc문자열의 위치를 알아내야하고, 찾아낸 문자열에 다른 문자는 섞이지 않았는지, 대문자는 아닌지 등 확인해야될 게 많다. 하지만 정규표현식을 사용하면 이 모든걸 한번에 해결할 수 있다.

 

정규표현식은 원하는 문자열을 쉽게 찾기 위해, 기존의 문자열을 다른 방식으로 쓰곤 한다.

. 의 경우 일반 문자에서는 마침표로 쓰이지만 정규표현식에서 .는 모든문자(줄바꿈은 제외)를 의미한다.

 

다른 뜻으로 쓰이는 문자를 메타 문자라고 하는데 사용하다보면 익숙해진다.

메타문자

 

메타문자는 12개가 있는데 일부만 설명하고 나머지는 파이썬과 함께 설명하도록 하겠다

 

마침표 ( . ) 메타문자 - 일치하는 모든 문자열 (1개)

첫번째 문자열은 a고, 마지막 문자열은 c인 문자열을 찾고 싶으면 어떻게 해야할까.

'abc', 'aec', 'afc' 같은 문자열을 모두 찾고 싶다면?

 

이때 사용하는게 마침표( . ) 메타문자이다. 마침표 (.) 가 있으면 어떤 문자가 있어도 일치하는 걸로 여긴다. 이때 새로줄 표시(\n)는 제외이기는 하다.

a.b처럼 적혀있으면 정규표현식에서는 a1baOb나 같은 패턴으로 여겨진다. 동일한 패턴을 찾기에 효과적인 방식이라 할 수 있다.

 

 

곱하기 (*) 메타문자 - 같은 문자열 반복

abbc, abbbc 처럼 같은 문자열이 반복되는 경우를 찾고 싶으면 어떻게 할까.

이때는 곱하기 (*) 메타문자를 쓰면 된다.

ab*c 처럼 적혀 있으면 b가 0개든, 1개든, 100개든 같은 패턴으로 여겨진다.

abcabbbbbbbbbbbbc 가 컴퓨터가 볼때는 같은 패턴인 것이다. 사람이 볼때는 다르지만.

 

이처럼 메타문자를 쓰면 일반적으로는 표현하지 못했던 패턴들을 적고, 찾아낼 수 있다.

그럼 파이썬에서 이런 정규표현식들이 어떻게 쓰이는지 알아보도록 하자.

 

더하기 (+) 메타문자 - 1개 이상 같은 문자열 반복

더하기 (+) 메타문자는 곱하기(*)와 유사하나 1가지 차이점이 있다.

1개 이상 문자열이 일치해야한다는 것이다.

a+c의 경우 abc 는 일치하는 패턴이지만 ac는 아니다

 

2. 파이썬에서의 정규표현식

2.1. re 모듈과 메서드

파이썬에서 정규표현식은 re 모듈를 써서 활용한다.

re 모듈에는 여러 함수가 있는데 주로 search, match, findall, compile을 사용한다.

각각의 사용법을 알아보자

match - 첫문자열부터 일치하는 패턴을 찾고 싶을때

문장에서 abc라는 문자열을 찾고 싶다면 어떻게 해야할까?

특히 첫단어부터 일치하는 경우만 찾고 싶다면, match 함수를 사용하면 된다.

 

match 함수의 사용법은 다음과 같다.

내가 검색하려는 문자열을 정해 2번째인자로 넣고, 패턴을 match함수의 첫번째 인자로 넣어주면 된다.

패턴( 예제에서는 abc )와 일치하는 문자가 있으면, m에 결과가 담기게 된다.

 

다른 예제를 보도록 하자

 

이번에는 a.c 를 패턴으로 썼다. 마침표 ( . )이 있으니 이 부분에는 아무 문자가 들어가도 된다.

문자열이 abcd1004이고 이 중에 abc이 일치하니 이 값을 출력하게 된다.

 

이제 정규표현식을 좀 더 배우면 파이썬으로 원하는 문자를 찾는 건 쉬울것 같다.

과연 그럴까?

다른 예제를 확인해보자

 

위의 예제를 실행하면 아무값도 나오지 않는다.

match 함수는 패턴이 문자열부터 일치해야지, 패턴을 찾은것으로 여기기 때문이다.

 

이처럼 match 함수는 일반적으로 쓰이기에는 무리가 있기에 search 함수를 자주 쓴다.

 

search - 아무곳에서나 일치하는 문자열을 찾고 싶을때

위의 예제를 search 함수를 써서 실행해보자

아무 문제 없이, 문자열 abc를 찾는다.

예제를 하나 더 보도록 하자

 

 

[a-f]e 을 찾고 싶은 패턴으로 썼는데, [] 는 여러 문자들 중 1개라도 일치하는지 확인하고 싶을때 쓰인다.

[abㅊ] 라고 되어 있으면 a와 b와 ㅊ 중 한개라도 일치하면 되는 것이다.

 

위의 예제에서는[a-f] 라고 적었는데 a-fabcdef 의 줄임말이다. ( 요런 특수 표시는 나중에 더 정리하겠다. )

[a-f]e 는 ae, be, ce, de, ee, fe 중 아무거나랑 하나라도 일치하는 것을 찾겠다는 뜻이다.

 

문자열 '123def789' 에는 de 가 들어 있으므로, 패턴을 찾는데 성공한다.

 

허나 search에도 문제가 있었으니, 일치하는 패턴을 1개만 찾을 수 있단 것이다.

 

find all - 패턴과 일치하는 여러 문자열을 찾고 싶을때

문자열에서 영어만 찾은 경우를 보자.

이때는 [a-zA-Z]+ 패턴을 쓰면 된다.

 

위의 예제를 실행하면 영어 hello가 출력된다.

영어를 잘 찾기는 했지만 모든 영어 문자를 찾지는 못한다.

 

모든 일치하는 문자열을 찾고 싶을때는 어떻게 해야할까. 이때 쓰이는 게 findall이다.

findall을 쓰면, 일치하는 모든 문자열을 찾아준다.

 

10만자 짜리 문서에서 이메일만 여러개 찾아보고 싶다면, 써야될게 바로 findall 이다.

 

2.2. 메타문자와 파이썬

 

이제 파이썬과 정규표현식에 익숙해졌으니, 나머지 메타문자를 알아보고 조금 더 복잡한 정규표현식을 작성해보도록 하자.

앞에서 알아본 메타문자에는 . * + []가 있었다.

 

? - 없거나 하나가 있을때

? 앞에 문자가 하나 있거나 없을때 매치가 된다.

go?d 의 경우

gdgod는 일치로 처리되지만

good는 일치가 아니다.

 

물음표 ( ? ) 메타문자 대신에 실제 물음표를 쓰려면 \? 식으로 적어주면 된다.

밑에서 자세히 알아보겠다.

 

{n, m} - 일정 갯수인 패턴 찾기

. * 메타문자를 쓰면 반복되는 문자를 찾을 수 있지만 갯수 제한이 없는게 단점이다.

만약 a가 4개, b가 2개인 문자열을 찾고 싶다면 어떻게 해야할까?

이때 사용하는게 { n, m } 메타문자이다.

여기서 n과 m은 숫자를 가리킨다.

{n,m} 앞의 문자열이 n번 이상, m번 이하 나타났다면 맞는 패턴으로 여겨진다.

x{2,5} 처럼 정규표현식이 적혀있다면, xx, xxx, xxxx , xxxxx 가 일치하는 패턴이 된다.

 

코드를 보며 좀 더 설명해보겠다

 

위의 코드를 보면 a{3,4} 가 정규식인데, 맞는 패턴을 찾을 수 있었기에 aaa 가 출력된다.

범위를 나타내는 정규표현식은 전화번호 찾기 등에 쓰일 수 있다.

휴대폰 번호는 일반적으로 11자리지만, 집전화의 경우 10자리인 경우도 있다.

이 경우 첫번째 전화 번호자리에 범위를 나타내는 정규식을 쓰면 쉽게 원하는 값만 추출할 수 있다.

 

예제의 첫번째 패턴을 보면 [0-9]{2,3}-[0-9]{4}-[0-9]{4} 로 적혀있다.

여기서 [0-9]{2,3} 는 숫자(0부터 9까지)가 2개 이상 3개 이하 있는 걸 말한다.

마찬가지로 [0-9]{4}는 숫자가 4개 있는 걸 말한다.

보통 전화번호 앞자리가 2자리거나 3자리이고, 뒷번호는 4자리씩이기에 이 정규식을 쓰면 전화번호를 적절히 찾을 수 있다.

하지만 완벽한건 아니고 - 가 없는 경우나 다른 기호() 가 들어가 있는 경우, 국제 번호인 경우는 처리하지 못한다.

 

^ - 시작 문자가 일치하는 경우 찾기

특정 문자로 시작하는지 확인하고 싶을때는 어떻게 해야할까

예컨데 어떤 문장이 '안녕'이란 말로 시작하는지 알고 싶다면?

 

이때 쓰이는게 ^ 메타문자이다.

^안녕 을 정규식으로 적었더니 '안녕하세요. 좋은 아침이에요' 란 문장에서

'안녕' 으로 매칭되는 걸 알 수 있다. '안녕하세요'가 문장의 맨 앞에 있기때문이다.

반면에 '안녕하세요'가 문장 안쪽에 있을때는 매칭이 안되는 걸 알 수 있다

 

^ 메타문자가 [] 안에서 쓰이면 다른 의미가 된다. 이 패턴은 제외한다는 뜻이 된다.

[0-9]가 숫자인 패턴을 찾는 거라면 , [^0-9] 는 숫자는 패턴을 제외한는 뜻이다.

 

$ - 마지막 문자가 일치하는 문자열 찾기

 

그럼 첫 문자가 아니라, 마지막 문자가 일치하는 경우를 찾고 싶다면 어떻게 해야할까.

예컨데 '요'로 끝나는 문장을 찾는 과제를 받았다고 상상해보자.

이때 $ 메타문자를 쓰면 된다

예시를 보자

 

'[ㄱ-힣]+요$' 정규식은 '요'로 끝나는 한글을 찾겠다는 의미이다.

[ㄱ-힣] 는 한글일때만 일치하는 걸로 본다는 뜻이고

요$ 는 '요'로 끝나는 경우만, 일치하는 걸로 여긴다.

'요'가 아니라 '요.' 이었으면 일치하지 않았을 것이다.

 

| - 여러개 조건 만족하는 패턴 찾기 (or, 또는)

정규식을 쓰다보면 여러 패턴과 일치하는지 확인하고 싶을때가 많다.

이때 쓰이는 게 | 메타문자이다.

| 앞 뒤에 적힌 정규식은 서로 다른 정규식으로 여겨진다.

 

| 를 쓰면 원하는 만큼 정규식을 적을 수 있다.

정규식1| 정규식2 | 정규식3 | ...

 

예를 보도록 하자

예에서 쓰인 정규식은 cro*w|bir+d으로 2개의 정규식이 연결되어 있다.

cro*wbir+d 중 하나만 일치해도, 맞는 패턴으로 본다.

There is a crow and bird 에는 crow가 일치하고 bird도 일치하는 문자열이기에

['crow', 'bird'] 가 결과로 출력된다.

 

() - 그룹으로 묶기

찾은 결과물에서 특정 부분만 빼내고 싶을때는 어떻게 해야할까.

예컨데 날짜를 찾았는데 연도랑 월만 빼내고 싶다면?

이 때 () 메타문자를 써서 그룹으로 묶으면 편리하다.

 

위의 예를 실행하면 2021-01-06 이 출력된다. 날짜를 찾아낸 것이다.

하지만 우리는 연도랑 월만 원한다.

이때 다른 함수로 문자열을 나눌 수도 있지만, () 로 묶어주면 구분하기 편리하다.

 

()로 묶어주고 나면

 

group(0) 을 쓰면 정규식과 일치하는 모든 문자를 다 가져온다.

 

group(1) 은 정규식과 일치하는 첫번째 문자를 찾아서 가져온다.

group(2)는 두번째, group(3)은 세번째인 식이다.

 

여기서는 2021이 첫번째 패턴인 ([0-9]{4}) 과 일치하기에

group(1) 은 2021를 출력한다.

 

그룹으로 만드는 방식은 우편번호 앞자리만 찾거나, 이메일의 도메인만 찾는다든지 할때 유용하다.

 

사실 그룹 기호가 섞인 정규식은 처음에 보면 꽤 헷갈리는데

() 없는 정규식을 만들어보고, 내가 () 기호를 써서 정규식을 만들어보는 식으로 연습하면은

점차 눈에 익게 된다.

 

메타문자 ( . ? $ )들을 원래 문자로 사용하기

물음표 (?)나 마침표(.)는 원래 문장에서도 쓰이는데 메타 문자로 쓰이고 있다.

이 메타문자들을 문자열로 쓰고 싶다면 앞에 \를 붙여주면 된다.

 

위의 예제를 보면 \? 를 쓰는가, ? 를 쓰는가에 따라

패턴이 매칭되는 곳이 달라진다.

m1에서는 \?가 패턴이기에 실제 ?가 있는 곳에서 매칭이 되지만

m2는 ?는 메타문자이기에 앞쪽, 물음표 기호가 없는 곳에서 매칭이 된다.

 

\문자 - 자주 쓰는 패턴을 나타낼때 사용한다

  • \d : 숫자인 경우, [0-9]와 같다
  • \D: 숫자가 아닌 경우, [^0-9] 와 같다.
  • \s: 공백 문자인 경우. 띄어쓰기나, 탭 (\t ), 새로운 줄(\n, \r)인 경우
  • \S : 공백 문자가 아닌 경우
  • \w: 숫자 및 알파벳 문자인 경우. [a-zA-Z0-9_] 와 같다
  • \W: 숫자 및 알파벳 문자가 아닌 경우. [^a-zA-Z0-9_] 와 같다

 

 

3.자주 쓰는 정규표현식 표현

 

이메일 찾기

 

문서에서 이메일만 찾고 싶을때가 있다.

이메일은 '@' 기호가 꼭 들어가고 영어 알파벳으로만 되어있다.

이를 고려하면 정규식은[\w]+@[\w]+ 처럼 될 것이다.

[\w]+ 은 알파벳이 1개 이상 있을때, 일치하는 걸로 본다는 뜻이다.

 

그런데 [\w]+@[\w]+만으로는 이메일을 모두 찾을 수 없다.

이메일에 . - 가 들어가 있는 경우가 있기 때문이다.

. -가 있어도 이메일을 찾을 수 있게 정규식을 바꾸면

[\w\.-]+@[\w\.-]+ 가 된다.

 

 

맞는 이메일인지 확인하기

 

회원 가입 페이지를 만들다 보면

맞는 이메일을 입력했는지 확인할 필요가 있다.

 

이때도 정규표현식을 쓰면은 편리하다.

일반적인 이메일은 알파벳및숫자@도메인이름 으로 되어 있다.

도메인 이름은 abc.com 처럼 com이나 co.kr 로 끝나는 주소를 말한다.

알파벳및숫자@도메인이름 중에서 알파뱃및 숫자를 정규식으로 표현하면 [a-z0-9]+ 이고

도메인 이름을 정규식 표현하면 \w+[.]\w+[.]?\w$이 된다.

\w+[.]\w+[.]?\w{2,4}$ 에서 \w[.] 까지는 도메인의 앞부분 ( naver.com에서 naver. 까지의 부분 )을 찾기 위함이다.

그 뒤의 \w+[.]? 은 도메인에 . 이 2개인 경우 ( naver.com은 .이 한개이지만, kbs.co.kr은 .이 두개이다 )를 찾기 위함이다.

[.]?. 이 있을 수도 있고 없을 수도 있다는 의미이다.

마지막으로 com, org, uk, kr 등의 최상위 도메인의 길이를 확인하면 되는데

\w{2,3}$ 정규표현식으로 확인하면 된다.

 

이를 다 합치면 정규식 ^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w+[.]?\w{2,3}$ 이 된다

 

 

 

한글 찾기, 한글 제거

 

한글 찾기는 []를 사용한다.

알파벳을 찾을때 [a-z] 를 써서 찾은 것처럼 [ㄱ-힣] 를 쓰면 한글을 찾을 수 있다.

 

 

 

마무리

 

정규표현식은 처음 배울때 난이도가 있지만

익혀두면 프로그래밍 언어에 상관없이 쓸 수 있어서 활용도가 높다.

간단한 식부터 써보면서 차근차근 익혀보도록 하자.

 


 

 

참고글 - 이메일 정규표현식으로 맞는지 확인하기

유용한 사이트 1 - 정규표현식 요약표 (Reg Cheet sheet)

유용한 사이트 2 - 온라인 정규표현식 연습 사이트

 

 

 

반응형
  1. 팜팜. 2021.01.18 14:39 신고

    안녕하세요 웹개발 초보입니다. 개발관련내용들이 워낙 다양해 관련해서 여쭙고 싶은데 여기 블로그를 통해 도움좀 받을 수 있을까요?

  2. 팜팜. 2021.01.18 14:47 신고

    현재 html+css+js+php 까지 공부했고, mySQL까지 마저 배워서 목표는 웹개발->하이브리드앱개발->크로스플랫폼앱개발이었습니다.

    그러다 최근 PWA에 대해서 알게되었는데요. 이는 하이브리드, 크로스플랫폼 앱을 다 아우르는 새로운 방식의 앱개발이라는 점이 상당히 매력적으로 다가와 웹개발이후 바로 pwa로 넘어갈까 생각중입니다.

    근데 궁금한것이 기존 웹개발을 html, css, js, php, mySQL로 해놓았다면 pwa로 개발을 할때 이 언어들이 다 연동이 되는지 아니면 새로 또 언어를 배워야하는건지 궁금합니다.

    • 에드 신 2021.01.18 15:41 신고

      pwa로는 제가 따로 개발을 해 본적이 없어서 말씀드리기가 조심스럽긴 하네요.

      pwa에 사용되는 프레임워크가 기존의 배웠던 것들이랑 관련이 있다면, 추가적으로 배워야할 양이 줄어들 것이고요.

      관련이 없는 프레임워크라면 새로 배울 게 많을 거에요.

      일반적으로는 새로 배워야할게 많은 편입니다.

    • 팜팜. 2021.01.18 16:11 신고

      답변 감사합니다.

+ Recent posts