Regular Expression
- 규칙, 패턴을 가진 문자열을 표현하는 방법
- 텍스트 처리 작업에 있어 아주 중요한 정규 표현식에 관한 문법 & 사용 정리. (Python re 패키지 기준)
1
import re
Navigator
- re.match
- re.search
- re.findall
- re.compile
- re.sub
- meta strings
- groups
- OR , AND
- greedy quantifier vs. lazy quantifier
re.match
1
re.match(검사패턴,입력 문자열)
세부내용 :
- 입력 문자열을 처음부터 검사하면서 검사패턴을 찾으면 정보를 반환하며 종료.
- 검사 도중 패턴 불일치가 일어나면 나머지 문자열에 대해서는 검사를 더이상 진행하지 않는다.
-
<re.Match object; span=(0, 5), match='hello'>와 같이span정보와 실제 찾은match정보를 반환해주며 , 일치 패턴이 없으면 반환값은 None 이다. - 매칭된 문자열을 반환 받으려면
re.Match object.group()메소드 활용
re.search
1
re.search(검사패턴,입력 문자열)
세부내용:
- match 와 거의 비슷하지만 패턴 매칭이 실패해도 문자열의 끝까지 계속 조사하며 일치 패턴을 발견하는 순간 조사가 종료된다.
- 입력 문자열에서 패턴이 여러번 존재하여도 패턴 일치와 함께 조사가 마무리되므로 가장 처음 등장하는 패턴 기준으로 반환된다.
-
span정보는 문자열에서 일치한 패턴이 시작과 끝 인덱스 정보를 담고 있다.
re.findall
1
re.findall(검사패턴 , 입력 문자열)
세부내용:
- 입력 문자열의 시작부터 끝까지 조사하면서 일치하는 모든 패턴을 리스트 형식으로 반환한다.
- match , search 와는 다르게 span 정보는 담겨 있지 않다.
-
finditer메소드를 활용하면span정보가 요소로 이루어진 반복 객체가 반환된다.
re.compile
1
pattern = re.compile('정규표현식')
세부내용:
- 패턴을 정의하여 패턴 객체를 생성할 수 있다.
- 패턴 객체를 활용하면 위의 메소드들을 re.match , re.search 대신
pattern.match(입력 문자열)의 형식으로 사용할 수 있다.
re.sub
1
re.sub(정규표현식 , 대체 문자열 , 입력 문자열)
세부내용:
- 파이썬 내장 문자열 대체 메소드인 replace 와 비슷한 작업을 수행하며 특정 단어가 아닌 정규표현식으로부터 매칭되는 모든 문자열을 대체 문자열로 바꾸는 작업이 가능하다.
- 이때 입력 문자열은 실제로는 변하지는 않고 대체 문자열로 바뀐 문자열이 반환된다.
meta strings
정규표현식을 구성하는 여러 메타 문자들의 사용법
[] (대괄호)
- 대괄호 내부에 있는 문자들과 매치
- ex. [abc] => 입력 : b (match) , d (fail)
- [A-Z] , [a-z] , [a-zA-z] : 각각 모든 대문자 알파벳 , 모든 소문자 알파벳 , 모든 알파벳 과 매치
- [0-9] , [가-힣] : 각각 모든 숫자 , 모든 한글과 매치
\ (역슬래시)
- 특수문자 일부를 메타문자가 아닌 그대로 쓰는 경우 혹은 특정 알파벳과 조합하여 집합의 의미를 가짐
- \d : 숫자 전체 그룹 , [0-9] 과 같은 의미
- \D : 대문자 활용은 Not 의 의미를 뜻함. 즉 숫자를 제외한 모든 문자와 매치 , [^0-9]
- \w : 모든 알파벳과 숫자 그룹 + _(언더바) , [a-zA-Z0-9_] 과 같은 의미
- \W : (알파벳 전체+숫자) 를 제외한 모든 글자와 매치 , [^a-zA-Z0-9]
- \s : 공백 문자 ( space , enter , tab)
- \+ , \* , \$ : 메타문자가 아닌 특수문자 그대로 패턴을 조사할 때 역슬래쉬를 붙임
+ , * , {} , ? (반복지정 메타 문자)
+ : 최소 1번 이상의 반복을 조사함
- 예) do+g ==> dog , doog, doooog (매치) , dg , doof (매치 없음)
* : 최소 0번 이상의 반복을 조사함
- 예) do*g ==> dg,dog,doog (매치) , df (매치 없음)
{} : 조사할 반복회수를 직접 숫자로 지정 (범위 지정도 가능)
- 예) do{2}g ==> doog (매치) , dog , dooog (매치 없음)
- 예2) do{1,3}g ==> dog , doog , dooog (매치) , doooog (매치 없음)
? : {0,1} 과 같은 의미로 없거나 최대 1번까지만 조사하는 반복 메타 문자
- 예) do?g ==> dg , dog (매치) , doog,dooog (매치 없음)
. (점)
- 어떤 글자도 매치하는 메타 문자.
- 예) d.g ==> dmg , dhg , drg (매치) , dgf , ddd (매치 없음)
- 점 자체의 문자로 표현식에 활용하려면
\.혹은[.]로 지정
^ , $ (시작과 끝 , 혹은 부정)
^ : 일반적인 사용은 해당 패턴으로 문자열이 시작하는지를 조사하는 메타문자. 대괄호 안에 쓰이면 NOT 의 의미로 쓰인다.
- ^dog ==> dog looks happy (매치) , that’s a cute dog (매치 없음)
- 특수문자 그대로 활용하려면
\^혹은[^]
$ : 문자열이 해당 패턴으로 끝나는지를 조사하는 메타문자.
- dog$ ==> that’s a cute dog (매치) , dog looks happy (매치 없음)
- 특수문자 그대로 활용하려면
\$혹은[$]
groups
정규 표현식을 이루는 세부 표현식들에 대하여 그룹이름을 부여한 뒤에 매치된 문자열로부터 그룹이름으로 참조할 수 있다.
1
( ?P<function name> 정규 표현식 일부)
1
2
3
pattern='(?P<letter>[a-zA-Z_]\w*)[(](?P<number>[a-zA-Z0-9,]*)[)]$'
res = re.match(pattern,'print(345,34)')
res.group('letter')
1
'print'
OR , AND
OR
1
pattern = '(group1)|(group2)'
AND :정식 표현은 아님 , 확장 표현
1
pattern = '(?=group1)(?=group2)'
탐욕적 수량자 vs. 게으른 수량자
정규표현식은 기본적으로 탐욕적 수량자에 의해 문자열을 탐색하기 때문에 특정 상황에서는 게으른 수량자를 통해 탐색할 필요가 있다.
PS 문제풀이 도중 , html 문자열을 parsing 하는 과정에서 의도치 않은 파싱이 일어나는 것을 보고 두 차이를 확인하였다.
1
2
3
4
import re
string_ = '''<a href="https://a.com" other="additional_info">'''
url_pattern = re.compile('''<a href="(.*)"''')
print("current url=",url_pattern.search(string_).group())
당연히 https://a.com 가 출력될줄 알았으나 결과는 다음과 같았다.
1
'current url= https://a.com" other="additional_info'
이는 기본 탐색 방식인 탐욕적 수량자는 전체 문자열을 탐색하고 표현식에 일치하는 가장 큰 길이의 문자열을 취하기 때문에 발생한다.
따라서 문자열 전체 탐색을 마치기 전에 표현식이 일치하는 순간 바로 탐색을 감지하려면 게으른 수량자를 통해 탐색을 진행해야한다.
게으른 수량자 적용 방법은 다음과 같이 탐욕적 수량자에
?를 붙여 사용하면 된다.
Greedy Quantifier
1
2
3
pattern = '(.*)'
pattern = '(.+)'
pattern = '(.{n,})'
Lazy Quantifier
1
2
3
pattern = '(.*?)'
pattern = '(.+?)'
pattern = '(.{n,}?)'
※ ? 기호가 단독으로 쓰이는 수량자와 헷갈리지 말자.