레이블이 regular expression인 게시물을 표시합니다. 모든 게시물 표시
레이블이 regular expression인 게시물을 표시합니다. 모든 게시물 표시

2022년 10월 19일 수요일

파이썬 정규식, Greedy Non Greedy탐색(최소일치/최대일치)

 이번엔 파이썬의 정규식(RegEx)중 Greedy match/Non-Greedy match부분을 설명합니다.

아래와 같은 예제에서 첫번째 괄호만 매치를 시키자고 하고합니다.

text = '(Machester 10) (London 20) (Seoul 30) (Tokyo 40)'

그렇지만, 실제로 아래와 같은 예제를 보면, 첫번째 괄호만 매치되는 게 아니라 마지막 괄호까지 전부 매치가 됩니다.

(.*) - Greedy match

(Manchester 10) (London  20) (Seoul 30) (Tokyo 40)

(.*?) - Non Greedy match (Manchester 10) (London  20) (Seoul 30) (Tokyo 40)

이것은 기본적으로 정규식은 Greedy match (최대한 많이 매치)를 하기 때문인데, 이렇게 되면 원래 의도와는 다른 결과가 나올 수 있습니다.

그래서 .* 뒤에 ?를 붙여서 .*? 과 같이 표현합니다. 그러면, 이 탐색자가 가장 많이 매치되는 경우를 찾아주는 것이 아니라 가장 적게 매치되는 경우를 찾아줍니다.

text = '(Machester 10) (London 20) (Seoul 30) (Tokyo 40)'
p = re.compile(r'(\(.*\))')
if m:= p.search(text): print (m.groups()) 
# ('(Machester 10) (London 20) (Seoul 30) (Tokyo 40)',)

p = re.compile(r'(\(.*?\))')
if m:= p.search(text): print (m.groups()) 
# ('(Machester 10)',)

이런 예는 종종 볼수 있습니다. 이것 말고도 HTML, XML match시킬때도 마찬가지 입니다. 또, C-style 주석도 이런 경우 종종 볼수 있습니다. /* ...  */ 와 같이 주석처리를 지우려고 하는데 , 텍스트 파일 전체가 지워지는 경우, 이 그리디매치가 적용이 되어서 그런것입니다.

가장 가까운 괄호와 매치시키고 싶은데, 반복자가 최대한 많이 매치시키려 하기 때문에, 이런 부분의 차이를 알고 있다면 정규식 쓰는데 좀더 활용도를 높일 수가 있습니다.

2019년 12월 10일 화요일

파이썬 정규식 regex Grouping



Grouping

정규식에서 ( )괄호는 그룹을 이야기합니다.
이 Grouping은 꽤 유용한 방법중의 하나입니다.

각각의 매칭을 MatchObject로 넘기며, 크게 아래와 같은 두가지 방법이 있습니다.

  1. 순서대로 가져오는 방법 
  2. 이름을 지정해서 가져 오는 방법


Ordered Group

이 중 순서대로 가져오는 방법은 group(0) : 전체,
group(1) : 첫번째 괄호
group(2) : 두번째 괄호
이런식으로 전개할 수 있으며, 아래와 같이 전화번호 같은 것을 매칭을 할떄,
아래와 같은 형태로 매칭이 됩니다.


import re
p = re.compile('([\d]+)_([\d]+)')
m = p.search('345-1234')
m.group(0) # 345-1234
m.group(1) # 345
m.group(2) # 1234




Named Groups

이름에 매핑하는 방법은, 아래와 같이 작성해서, dictionary로 반환을 받는 방법입니다.
(?P<name>pattern)


import re
p = re.compile('(?P[\d]+)_(?P[\d]+)')
m = p.search('345-1234')
m.group(0) # 345-1234
m['first'] # 345
m['second'] # 1234

정규식에서 다시 값을 추출해서 특정 용도로 사용할때 , 중간단계를 사라지게 해서
편한 방법중 하나 입니다.


Back references 

back referencing(역참조)의 \1은 처음 사용한 표현식과 일치한다는 이야기입니다.
마찬가지로 \2, \3은 두번째 세번째 사용한 표현식과 일치한다는 것이고,
이 것은 주로 패턴이 반복되어서 나올때에 사용합니다

그리고, substitute (치환)을 할때, 매칭을 다시 가져다 쓸 때 사용합니다.
주로 언제 사용하냐면 순서를 바꿀때, 예를 들면, 첫번째 매칭이랑 두번째 매칭을 순서를 바꿀때, 이 방법이 유용합니다.

import re
p = re.compile('(?P[\d]+)_(?P[\d]+)')
m = p.sub('P\2_M\1','345-1234')
m # P1234_M345