Posts Regular Expression
Post
Cancel

Regular Expression

Regular Expression

  • 규칙, 패턴을 가진 문자열을 표현하는 방법
  • 텍스트 처리 작업에 있어 아주 중요한 정규 표현식에 관한 문법 & 사용 정리. (Python re 패키지 기준)
1
import re

:arrow_right: re.match

1
re.match(검사패턴,입력 문자열)

세부내용 :

  • 입력 문자열을 처음부터 검사하면서 검사패턴을 찾으면 정보를 반환하며 종료.
  • 검사 도중 패턴 불일치가 일어나면 나머지 문자열에 대해서는 검사를 더이상 진행하지 않는다.
  • <re.Match object; span=(0, 5), match='hello'> 와 같이 span 정보와 실제 찾은 match 정보를 반환해주며 , 일치 패턴이 없으면 반환값은 None 이다.
  • 매칭된 문자열을 반환 받으려면 re.Match object.group() 메소드 활용

:arrow_right: re.search

1
re.search(검사패턴,입력 문자열)

세부내용:

  • match 와 거의 비슷하지만 패턴 매칭이 실패해도 문자열의 끝까지 계속 조사하며 일치 패턴을 발견하는 순간 조사가 종료된다.
  • 입력 문자열에서 패턴이 여러번 존재하여도 패턴 일치와 함께 조사가 마무리되므로 가장 처음 등장하는 패턴 기준으로 반환된다.
  • span 정보는 문자열에서 일치한 패턴이 시작과 끝 인덱스 정보를 담고 있다.

:arrow_right:re.findall

1
re.findall(검사패턴 , 입력 문자열)

세부내용:

  • 입력 문자열의 시작부터 끝까지 조사하면서 일치하는 모든 패턴을 리스트 형식으로 반환한다.
  • match , search 와는 다르게 span 정보는 담겨 있지 않다.
  • finditer 메소드를 활용하면 span 정보가 요소로 이루어진 반복 객체가 반환된다.

:arrow_right:re.compile

1
pattern = re.compile('정규표현식')

세부내용:

  • 패턴을 정의하여 패턴 객체를 생성할 수 있다.
  • 패턴 객체를 활용하면 위의 메소드들을 re.match , re.search 대신 pattern.match(입력 문자열) 의 형식으로 사용할 수 있다.

:arrow_right: re.sub

1
re.sub(정규표현식 , 대체 문자열 , 입력 문자열)

세부내용:

  • 파이썬 내장 문자열 대체 메소드인 replace 와 비슷한 작업을 수행하며 특정 단어가 아닌 정규표현식으로부터 매칭되는 모든 문자열을 대체 문자열로 바꾸는 작업이 가능하다.
  • 이때 입력 문자열은 실제로는 변하지는 않고 대체 문자열로 바뀐 문자열이 반환된다.

:arrow_right: meta strings

정규표현식을 구성하는 여러 메타 문자들의 사용법

:pen: [] (대괄호)

  • 대괄호 내부에 있는 문자들과 매치
  • ex. [abc] => 입력 : b (match) , d (fail)
  • [A-Z] , [a-z] , [a-zA-z] : 각각 모든 대문자 알파벳 , 모든 소문자 알파벳 , 모든 알파벳 과 매치
  • [0-9] , [가-힣] : 각각 모든 숫자 , 모든 한글과 매치

:pen: \ (역슬래시)

  • 특수문자 일부를 메타문자가 아닌 그대로 쓰는 경우 혹은 특정 알파벳과 조합하여 집합의 의미를 가짐
  • \d : 숫자 전체 그룹 , [0-9] 과 같은 의미
  • \D : 대문자 활용은 Not 의 의미를 뜻함. 즉 숫자를 제외한 모든 문자와 매치 , [^0-9]
  • \w : 모든 알파벳과 숫자 그룹 + _(언더바) , [a-zA-Z0-9_] 과 같은 의미
  • \W : (알파벳 전체+숫자) 를 제외한 모든 글자와 매치 , [^a-zA-Z0-9]
  • \s : 공백 문자 ( space , enter , tab)
  • \+ , \* , \$ : 메타문자가 아닌 특수문자 그대로 패턴을 조사할 때 역슬래쉬를 붙임

:pen: + , * , {} , ? (반복지정 메타 문자)

+ : 최소 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 (매치 없음)

:pen: . (점)

  • 어떤 글자도 매치하는 메타 문자.
  • 예) d.g ==> dmg , dhg , drg (매치) , dgf , ddd (매치 없음)
  • 점 자체의 문자로 표현식에 활용하려면 \. 혹은 [.] 로 지정

:pen: ^ , $ (시작과 끝 , 혹은 부정)

^ : 일반적인 사용은 해당 패턴으로 문자열이 시작하는지를 조사하는 메타문자. 대괄호 안에 쓰이면 NOT 의 의미로 쓰인다.

  • ^dog ==> dog looks happy (매치) , that’s a cute dog (매치 없음)
  • 특수문자 그대로 활용하려면 \^ 혹은 [^]

$ : 문자열이 해당 패턴으로 끝나는지를 조사하는 메타문자.

  • dog$ ==> that’s a cute dog (매치) , dog looks happy (매치 없음)
  • 특수문자 그대로 활용하려면 \$ 혹은 [$]

:arrow_right: 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'


:arrow_right: OR , AND

:pen: OR

1
pattern = '(group1)|(group2)'

:pen: AND :정식 표현은 아님 , 확장 표현

1
pattern = '(?=group1)(?=group2)'


:arrow_right: 탐욕적 수량자 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'

이는 기본 탐색 방식인 탐욕적 수량자는 전체 문자열을 탐색하고 표현식에 일치하는 가장 큰 길이의 문자열을 취하기 때문에 발생한다.

따라서 문자열 전체 탐색을 마치기 전에 표현식이 일치하는 순간 바로 탐색을 감지하려면 게으른 수량자를 통해 탐색을 진행해야한다.

게으른 수량자 적용 방법은 다음과 같이 탐욕적 수량자에 ? 를 붙여 사용하면 된다.

:pen: Greedy Quantifier

1
2
3
pattern = '(.*)'
pattern = '(.+)'
pattern = '(.{n,})'

:pen: Lazy Quantifier

1
2
3
pattern = '(.*?)'
pattern = '(.+?)'
pattern = '(.{n,}?)'

? 기호가 단독으로 쓰이는 수량자와 헷갈리지 말자.


This post is licensed under CC BY 4.0 by the author.