본문 바로가기

코딩/Python

[Python/파이썬]문자열 처리 정규 표현식(regular expression) - 3 : 긍정형 전방탐색, 긍정형 후방탐색

반응형

1편 : 2022.08.11 - [코딩/Python] - [Python/파이썬] 문자열 처리 정규 표현식(regular expression) - 1

2편 : 2022.09.03 - [코딩/Python] - [Python/파이썬] 문자열 처리 정규 표현식(regular expression) - 2 : 실제 예시를 통한 이해

3편 : 2022.10.25 - [코딩/Python] - [Python/파이썬]문자열 처리 정규 표현식(regular expression) - 3 : 전방탐색, 후방탐색

 

 

  C 코드 파싱 진행시 문제가 있었던 부분이 있어 해결방법과 내용을 정리하였다. C 코드 중 변수 타입의 라인들은 모두 매치시키려고 했었고 아래 경우는 var = 변수값; 형태의 문자열을 모두 매치시킨다.

 

 

<코드>

import re

txt1 = "double load_var = 10;"
txt2 = "double var = 10;"
txt3 = "int var = 30;"
txt4 = "var = 30;"

txt_list = [txt1, txt2, txt3, txt4] #위 TXT를 리스트로 정의
 
#var = 변수값; 형태의 문자열을 매치시키는 정규표현식
for txt in txt_list:
    match1= re.search("(var = )[0-9]+", txt)
    print(match1)

 

<결과>

<re.Match object; span=(12, 20), match='var = 10'>
<re.Match object; span=(7, 15), match='var = 10'>
<re.Match object; span=(4, 12), match='var = 30'>
<re.Match object; span=(0, 8), match='var = 30'>

 

  위 txt1~txt4는 var = 숫자; 형태의 변수 설정 라인들이다. 내가 원했던 것은 "var"라는 변수의 형태만을 추출하고 싶었는데 결과에서 보면 load_var = 10;의 형태도 같이 매치되었다. 이런 경우 정규표현식에서 해결할 수 있는 방법은 전방탐색 구문과 후방탐색 구문을 적용하는 것이다.

 

  먼저 전방탐색과 후방탐색을 정리해보자.

 

1. (긍정형)전방 탐색 구문(lookahead)

 

 많은 블로그 내용과 책들을 참고해보니 정규표현식에서 '문자열을 소비한다', '문자열을 소비하지 않는다'라는 설명이 많다. 간단히 설명하면 위와 같은 경우 정규표현식 구문은 (var = )[0-9]+로 작성되었고 txt1~txt4의 문자열들은 해당 패턴이 매치되어 결과값이 반환되었다. 이 경우를 일치하는 영역을 '해당 문자열을 소비한다'라고 표현한다.

 

  즉, 소비한다 = '해당 정규표현식 패턴에 매치되어 문자열을 반환한다'이다. 반대로 소비하지 않는다라는 개념은 '패턴에 매치되지만 문자열을 반환하지 않는다'라는 것으로 이해하면 된다.

 

  전방탐색은 앞에 있는 문자들은 반환하며, 뒤에 있는 어떤 특정 규칙의 문자는 반환하지 않을 때 사용한다.(패턴에 매치되지 않지만 반환하지 않는다는 의미) 아래 예시를 통해 정리해보았다.

 

  먼저 전방탐색 사용방법은 아래와 같다. (?= )와 같이 사용한다.

 

'Patter1'(?='Pattern2')

 

 

'Pattern1' : 패턴에 매치되어 반환되어야 할 부분

(?='Pattern2') : 패턴에 매치되지만 반환되지 않을 부분

 

 

 

초반에 예시로 들었던 txt1~txt4 예시에서 2가지 예시를 추가하였다.

 

txt1 = "double load_var = 10;"
txt2 = "double var = 10;"
txt3 = "int var = 30;"
txt4 = "var = 30;"
txt5 = "double practice;"
txt6 = "int practice;"

 

위 예시에서 아래 조건에 부합하는 경우만 찾아보자.

1) double 형태일 것

2) 변수값이 지정되어있어야 하지만, 실제 출력은 되면 안됨.

 

ex) double load_var = 10; -> double load_var 형태만 출력할 것

 

 

 

전방탐색 구문을 사용하여 패턴을 다시 작성해보면

 

<코드>

import re

txt1 = "double load_var = 10;"
txt2 = "double var = 10;"
txt3 = "int var = 30;"
txt4 = "var = 30;"
txt5 = "double practice;"
txt6 = "int practice;"

txt_list = [txt1, txt2, txt3, txt4, txt5, txt6]

#Double 형태의 변수들만 받아오기(duble)빼고

for txt in txt_list:
    match1= re.search("(double).+(?=(\s=\s[0-9]+))", txt)
    print(txt)
    print(match1)
    print()

 

<결과>

double load_var = 10;
<re.Match object; span=(0, 15), match='double load_var'>

double var = 10;
<re.Match object; span=(0, 10), match='double var'>

int var = 30;
None

var = 30;
None

double practice;
None

int practice;
None

 

txt1, txt2만 매치된 것을 확인할 수 있다. 요소요소를 쪼개보면

 

(double).+(?=(\s=\s[0-9]+))

 

1) (double) : 앞에 "double" 문자열이 있어야 함.

2) .+ : 점(.)의 경우 '아무거나 상관없다'라는 의미이고 뒤에 +는 1개이상이라는 의미이다. 즉, 어떤 문자든 1개이상 나온다.

3) (?=(\s=\s[0-9\+)) : 전방탐색 구문으로 해당 구문에 매치되지만 실제 반환은 하지 않는다.

 

 

?= : 전방탐색 구문

\s : space(띄어쓰기 1칸)

[0-9]+ : 숫자 형태 1개 이상

 

 

 

2. (긍정형)후방 탐색 구문(lookbehind)

 

  전방탐색과 반대로 문자열 앞 부분에서는 매치되지만 반환하지 않고, 뒤에 부분만 반환하는 구문이다. 후방 탐색의 사용 구문은 아래와 같다.

 

(?<='pattern1')'pattern2'

 

'pattern1' : 앞 부분에서 패턴에 매치되지만 반환하지 않을 부분

'pattern2' : 패턴에 매치되고 반환할 부분

 

 

마찬가지로 아래 예시에서 아래조건에 해당하는 구문을 작성해보자. 후방탐색을 설명하기 위해 예시를 좀더 추가하였다.

 

1) 앞에 변수 자료형은 패턴에 매치되지만 결과에 반환하지 않는다.

2) 뒤에 변수명과 변수값 모두 출력한다.

 

 

<코드>

import re

txt1 = "double load_var = 10;"
txt2 = "double var = 10;"
txt3 = "int var = 30;"
txt4 = "var = 30;"
txt5 = "double practice;"
txt6 = "int practice;"

txt_list = [txt1, txt2, txt3, txt4, txt5, txt6]

#Double 형태의 변수들만 받아오기(duble)빼고

for txt in txt_list:
    match1= re.search("(?<=double\s).+|(?<=int\s).+", txt)
    print(txt)
    print(match1)
    print()

 

<결과>

double load_var = 10;
<re.Match object; span=(7, 21), match='load_var = 10;'>

double var = 10;
<re.Match object; span=(7, 16), match='var = 10;'>

int var = 30;
<re.Match object; span=(4, 13), match='var = 30;'>

var = 30;
None

double practice;
<re.Match object; span=(7, 16), match='practice;'>

int practice;
<re.Match object; span=(4, 13), match='practice;'>

 

- 앞에 int나 double이 있는 형태는 매치되고 match 결과는 자료형이 반환되지 않음

- 앞에 double이나 int가 없는 txt4="var = 30"의 경우 매치되지 않은 것을 확인할 수 있다.

 
(?<=double\s).+|(?<=int\s).+

 

  위 구문 중 가운데 |은 OR의 의미이다. OR의 의미를 고려하면 (double\s) 또는 (int\s)가 매치되지만 결과로는 반환되지 않는 후방 타맥 구문이다.

 

 

 

3. 기타 

 

-  공부하면서 알게된건데 전방탐색 구문과 후방탐색 구문 안에는 사이즈가 변경되는 구문을 작성하지 못하는 것 같다. 정규표현식 매치에서 + , ?, {1,} 과 같이 문자 몇개 이상 이라는 구문을 작성하는데 이런 부분은 아래와 같은 오류가 뜬다.

- 아래 에러 내용에 따르면 look-behind(또는 look-ahead)는 정해진 길이의 패턴만을 허용한다는 의미이다.

 

error : look-behind requires fixed-width pattern

 

 

- 전방탐색 후방탐색 구문은 긍정형 이외에도 부정형이 있다. 긍정형은 위와 같이 패턴에 일치하는 경우 소비하지 않는 내용이고 부정형은 패턴에 일치하지 않는 텍스트이다. 아직 적용할 예시를 찾지 못해서 부정형에 대해서는 향후에 필요할 때 포스팅 예정

728x90