세상을 더 편리하게
728x90
import re

data = """
park 800905-1049118
kim  700905-1059119
"""

pat = re.compile("(\d{6})[-](\d{7})")
print(pat.sub("\g<1>-******", data))

#park 800905-*******
#kim  700905-*******

위의 코드는 정규식을 이용해서 주민번호를 받아서 뒷자리를 *로 만들어주는 코드이다. 

무엇인지는 몰라도 되게 간결하다. 

정규식은 일종의 필터(여과지)라고 생각하면 된다.

그럼 무엇을 여과 할 수 있는지 알아보자.

문자 클래스 [ ]

[(필터하길 바라는 것들)]

[abc]
#1. a -> Yes
#2. bread -> Yes
#3. dude -> No

1번은 abc 중 a 를 포함하기에 Yes

2번은 bread 중 b a 를 포함하기에 Yes

3번 dude 중 abc 어느 것도 없기에 No

[a-z]
# a 에서 z까지의 포함된 언어를 뜻한다.
[a-zA-Z]
# a 에서 z까지와 A에서 Z까지 즉 모든 알파벳을 포함한다.
[4-9]
# 4부터 9까지 숫자를 포함한다.

이외의 자주 사용하는 문자클래스가 있다.

정규 표현식

설명

정규 표현식

설명

\d

[0-9]

\D

숫자가 아닌 모든 것

\s

여백을 의미한다.

\S

여백이 아닌 모든 것

\w

문자 + 숫자[a-zA-Z0-9]

\W

문자 숫자 아닌 모든 것

위의 표를 보면 소문자와 대문자는 반대를 의미한다.

문자클래스에서 ^의 의미

^는 문자열의 시작을 의미한다. [^python] 은 python으로 시작하는 문자열이여야 한다는 의미이다.

Dot ( . )

[a.b] 는 "a + 모든 문자 + b" 와 같은 의미이다.

[a.b]
#1.a0b -> Yes
#2.aab -> Yes
#3.abc -> No

3번을 보면 a와 b 사이에 아무것도 없으므로 정규식을 충족시키지 못했다.

반복 ( *  / + / { } / ? )

[do*g] 는 d와 g사이에 o를 0번이상 반복한다는 뜻이다.

[do*g]
#1.dg -> Yes
#2.dog -> Yes
#3.doooooog -> Yes

위의 예시를 보면 o 가 없어도 되고 여러개 있어도 조건을 충족한다.

[do+g] 는 d와 g사이에 o를 1번 이상 반복한다는 뜻이다.

[do+g]
#1.dg -> No
#2.dog -> Yes
#3.doooooog -> Yes

1번을 보면 o가 0개 이므로 조건을 충족시키지 못했다.

[do?g] 는 d와 g사이에 o를 0번 혹은 1번 반복한다는 뜻이다.

[do?g]
#1.dg -> Yes
#2.dog -> Yes
#3.doooooog -> No

3번은 o 가 6번 반복되었으므로 조건을 충조시키지 못했다.

[do{2}g]
#1-1.dg -> No
#1-2.dog -> No
#1-3.doooooog -> No ( o 6번 반복 )

[do{2,8}g]
#2-1.dg -> No
#2-2.dog -> No
#2-3.doooooog -> Yes ( o 6번 반복 )

첫 예제는 반드시 d와 g 사이에 o가 2번 반복되어야 한다는 것을 의미한다.

두번째 예제는 o 가 2 ~ 8번 반복되어야 조건을 충족시킨다는 것을 의미한다.

정규표현식의 사용

위에서 배운 정규 표현식을 사용하는 방법은 re 모듈을 사용한다 [ re = Regular Expressing ]

p = re.compile(정규표현식)

컴파일된 패턴 객체(p)가 사용할 수 있는 함수는 총 4가지이다.

match()

문자열의 처음부터 정규식과 매치되는지 조사하고 맞으면 match 객체를 반환한다.

import re

p = re.compile('[a-z]+')
m = p.match('python')
print(m) #<re.Match object; span=(0, 6), match='python'>

위의 코드를 보면 python 문자열은 정규표현식에 부합하므로 match 가 반환되었다.

import re

p = re.compile('[a-z]+')
m = p.match('5python')
print(m) #None

정규식에 부합하지 않으면 None 이 반환된다.

search()

import re

p = re.compile('[a-z]+')
m = p.search('python')
print(m) #<re.Match object; span=(0, 6), match='python'>

search도 부합하면 Match 객체를 반환한다.

import re

p = re.compile('[a-z]+')
m = p.search('5python')
print(m) #<re.Match object; span=(1, 7), match='python'>

search 는 match 함수와 다르게 일부분이 충족해도 Match 객체를 반환해준다.

findall()

import re

p = re.compile('[a-z]+')
m = p.findall('life is too short')
print(m) #['life', 'is', 'too', 'short']

findall 함수는 조건에 충족하는 각 단어들을 리스트로 반환시켜 준다.

finditer()

import re

p = re.compile('[a-z]+')
m = p.finditer('life is too short')
for i in m:
    print(i)
"""
<re.Match object; span=(0, 4), match='life'>
<re.Match object; span=(5, 7), match='is'>
<re.Match object; span=(8, 11), match='too'>
<re.Match object; span=(12, 17), match='short'>
"""

finditer 함수는 findall 과 비슷하지만 반환을 반복 가능한 객체로 리턴한다. 각 요소는 match 객체이다.

 

match 객체의 함수

 위에서 보면 알 수 있듯이 re 모듈로 이용한 패턴 객체는 대부분 match 객체로 리턴 되는 것을 알 수 있다.

그럼 match 객체의 함수를 살펴보자.

group()

 그룹은 매치된 문자열을 반복한다.

import re

p = re.compile('[a-z]+')
m = p.search('5python')
print(m.group()) #python

start() / end()

매치된 문자열의 시작/끝의 인덱스를 리턴한다.

span()

매치된 문자열의 (시작,끝) 형식 튜플을 리턴한다.

re 모듈 complie 옵션

p = re.compile(정규표현식)

p = re.complie(정규표현식, 옵션)

위의 내용에 정규표현식은 위에처럼 표현한다고 했다. 하지만 여기에 옵션을 넣어서 더 좋은 필터여과지를 만들 수 있다.

  • DOTALL(S) - . 이 줄바꿈 문자를 포함하여 모든 문자와 매치할 수 있도록 한다.
  • IGNORECASE(I) - 대소문자에 관계없이 매치할 수 있도록 한다.
  • MULTILINE(M) - 여러줄과 매치할 수 있도록 한다. (^, $ 메타문자의 사용과 관계가 있는 옵션이다)
  • VERBOSE(X) - verbose 모드를 사용할 수 있도록 한다. (정규식을 보기 편하게 만들수 있고 주석등을 사용할 수 있게된다.)

[ ( ) 는 약어 ]

DOTALL / S

import re

p = re.compile('a.b')
m = p.match('a\nb')
print(m) #None

위에 보면 개행문자(\n) 는 a.b 정규 표현식에 성립하지 못하는 것을 알수 있다.

import re

p = re.compile('a.b', re.S)
m = p.match('a\nb')
print(m.group()) 
#a
#b

하지만 옵션을 넣어서 정규 표현식에 만족하게 만들 수 있다.

IGNORECASE / I

import re

p = re.compile('a.b', re.I)
m = p.match('A5B')
print(m.group()) #A5B

MULTILINE / M

import re

data = """python one
life is too short
python two
you need python
python three
"""
p = re.compile('^python\s\w+')
m = p.findall(data)
print(m)  # ['python one']

위의 코드를 보면 정규 표현식은

  1. python 으로 시작하는 문자열 

  2. python (공백)아무문자

라는 공식을 갖고 있다.

하지만 프린트 해보면 첫 줄 밖에 출력이 되지 않는다.

import re

data = """python one
life is too short
python two
you need python
python three
"""
p = re.compile('^python\s\w+', re.MULTILINE)
m = p.findall(data)
print(m)  # ['python one', 'python two', 'python three']

하지만, MULTILINE 옵션을 추가하면 다중 문자열 모두를 검색해 준다.

VERBOSE / X

import re

p = re.compile("""
a  # 주석1
.  # 주석2
b  # 주석3
""", re.VERBOSE)
m = p.search('aeb')
print(m.group())  # aeb

컴파일 함수 안의 정규 표현식이 다중 문자열로 표현했지만, 개행 문자와 주석을 피하고 정규 표현식으로 인식하고 실행되었다.

이처럼 정규 표현식이 길어질 때에는 다중 문자열로 하나씩 주석을 달아서 복잡한 정규 표현식도 보기 쉽게 사용 할 수 있다.

이 때, 옵션에 VERBOSE를 사용한다.

 

 

 

 

 

 

728x90
profile

세상을 더 편리하게

@쵱니

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!