본문 바로가기
Tech Stack/Python

정규표현식 (2)

by jaeaemin 2021. 8. 14.

 

 메타 문자

 

|

' | ' 문자는 or 과 동일한 의미롤 사용되는 메타 문자로 A | BA 또는 B 라는 의미를 갖는다.

 

>>> p = re.compile('Crow|Servo'
>>> m = p.match('CrowHello'
>>> print(m)
<re.Match object; span=(0,4), match='Crow'>

 

 

^

' | ' 문자는 문자열의 맨 처음과 일치한다는 것을 의미한다. ^Life life로 시작하는 문자열의 의미를 갖는다.

 

>> print(re.search('^Life''Life is too short'))
<re.Match object;  span =(04), match='Life'
>>> print(re.search('^Life''My Life')) 
None

>> print(re.search('^Life', 'Life is too short')) <re.Match object; span=(0, 4), match='Life'> >>> print(re.search('^Life', 'My Life')) None

^Life 정규식은 Life 문자열이 처음에 온 경우에는 매치하지만 처음 위치가 아닌 경우에는 매치되지 않음을 알 수 있다.

 

 

$

$ 메타 문자는 ^ 메타 문자와 반대의 경우로.  $는 문자열의 끝과 매치함을 의미한다. short$short로 끝나는 문자열의 의미를 갖는다.

 

>>> print(re.search('short$''Life is too short'))
<re.Match object; span =(1217), match='short'>
>> 
print(re.search('short$''Life is too short, you need python'))
 None

 ^ 또는 $ 문자를 메타 문자가 아닌 문자 그 자체로 매치하고 싶은 경우에는 \^, \$ 로 사용하면 된다.

 

\ ?

 

\A 문자열의 처음과 매치됨을 의미한다. 
re.MULTILINE 옵션을 사용하여도 \A 는 줄에 적용되는 것이 아닌 전체 문자열에 대해서 적용된다.
\Z 문자열의 끄톼 매치된다. \A와 동일하게 re.MULTILINE옵션에서도 전체 문자열에 대해 적용된다.
\b 단어 구분자로 보통 단어는 whiltespace에 의해 구분된다. 이는 따라서 단어의 whiltespace에 따라 매칭된다.
>> p = re.compile(r'\bclass\b') 
>>> print(p.search('no class at all'))                     # 클래스의 앞뒤로 \b = whitespace 이므로 매칭 O
<re.Match object; span=(
3, 8), match='class'>

>>> print(p.search('one subclass is')).    # 앞에 whitespace가 아닌 'sub'로 매칭 X
 
None
\B \b와 반대의 경우로 whiltespacer가 위치에 들어오게 되면 매칭이 되지 않고 다른 문자열이나 숫자가 들어오면 
매칭이 된다.


 

 

 

 

 

그루핑 

 

어떤 매칭되는 문자열에 대한 반복을 찾기 위해서는 ( ) 를 이용한 그루핑을 통해서 정규식을 구현할 수 있다.

cat이라는 단어에 대해서 그루핑을 하고 싶다면 (cat)+ 이라고 작성할 수 있다. 즉 ()는 그룹을 만들어주는 메타문자이다.

 

 

>>> p = re.compile('(ABC)+')
 >>> m = p.search('ABCABCABC OK?')
 >>> print(m)
<re.Match object; span=(0, 9), match='ABCABCABC'> >

>> 
print(m.group())
ABCABCABC

예시에서 처럼 ABC가 0번째부터 9번째 인덱스까지 추출되어서 group으로 묶인 것을 확인할 수 있다.

 

 

이번에는 이름 + "" + 전화번호의 형태의 문자열의 정규식에서 이름을 추출하기 위해서 어떻게 해야할까? 이 때 그루핑을 사용할 수 있다.

 

>>> p = re.compile(r"\w+\s+\d+[-]\d+[-]\d+"
>>> m = p.search("park 010-1234-1234")

>>> p = re.compile(r"(\w+)\s+\d+[-]\d+[-]\d+"
>>> m = p.search("park 010-1234-1234"
>>> print(m.group(1))
park

 

위의 예시에서 보면 이름에 해당하는 \w 부분을 그룹 (\w+)으로 만들면 match 객체의 group 메서드를 사용하여 그루핑된 부분의 문자열이 추출된다. group 메서드에서 각 인덱스는 아래와 같은 의미를 지닌다.

  • group(0)     :      매치된 전체 문자열
  • group(1)      :      첫 번째 그룹에 해당되는 문자열
  • group(2)     :      두 번째 그룹에 해당되는 무자열
  • group(n)     :       n번째 그룹에 해당되는 문자열

 

그렇다면 이런식으로 전화번호를 그룹2로 추가하여 추출한다면 아래의 코드와 같을 것이다.

>>> p = re.compile(r"(\w+)\s+(\d+[-]\d+[-]\d+)")
 >>> m = p.search("park 010-1234-1234"
>>> print(m.group(2)) 010-1234-1234

 

(w+)의 이름부분을 포함해서 추가로  (\d+[-]\d+[-]\d+)의 전화번호 그룹을 만들었다. 이 상태에서 group(2)처럼 사용하면 전화번호만 그루핑 되어 추출할 수 있다.

추가로 만약 국번을 따로 그룹3으로 추출한다면 "(\w+)\s+(\d+[-]\d+[-]\d+)" 에서 "(\w+)\s+( ( \d )+[-]\d+[-]\d+)으로 한다면 group(3)에는 국번만 따로 추출되게 된다.  ( 중첩 그룹에서는 바깥족부터 안쪽까지 그룹 인덱스 번호가 증가한다. )

 

 

 

그루핑된 문자열음 재참조를 할 수 있는 특징을 가진다.

>>> p = re.compile(r'(\b\w+)\s+\1') 
>>> p.search('Paris in the the rain').group() 
'the the'

정규식 (\b\w+)\s+\1은 (그룹) + " " + 그룹과 동일한 단어와 매치됨을 의미한다. 이렇게 정규식을 만들게 되면 2개의 동일한 단어를 연속적으로 사용해야만 매치된다. 

즉  \1 은 그룹 중 첫번째를 가리키로  \2는 두번째  \n은 그룹 중 n번째를 가리킨다. 

 

 

 

그루핑은 그룹들의 구별을 위해 별명을 지을 수 잇는 특징도 가진다.

 

(?P<name>\w+)\s+((\d+)[-]\d+[-]\d+)

 

위 정규식은 앞에서 본 이름과 전화번호를 추출하는 정규식이다. 기존과 달라진 부분은 다음과 같다.

(\w+) --> (?P<name>\w+)

이는 (\w+)라는 그룹에 name이라는 이름을 붙여준 것이다. 이 때 ?..은 정규표현식의 확장 구문으로 가동성이 조금 떨어지지만 강력함을 갖춘 구문이다.

일단 그룹에 이름을 짓는 방법은  (?P<그룹명>...) 을 사용하면 된다.

 

>>> p = re.compile(r"(?P<name>\w+)\s+((\d+)[-]\d+[-]\d+)"
>>> m = p.search("park 010-1234-1234"
>>> print(m.group("name"))       # name이라는 이름으로 group(1)을 추출함
park


물론 재 참조도 가능하다.
>>> p = re.compile(r'(?P<word>\b\w+)\s+(?P=word)'
>>> p.search('Paris in the the spring').group() 
'the the'

 

여기서 알아봐야 할 점은 선언시 와 다르게  재참조할 때에는 (?P=그룹이름)이라는 확장 구문을 사용해야 한다.

 

 

전방 탐색

반응형

'Tech Stack > Python' 카테고리의 다른 글

정규 표현식  (0) 2021.08.13
내장함수  (0) 2021.08.10
예외 처리  (0) 2021.08.06
패키지  (0) 2021.08.03
모듈  (0) 2021.08.02