본문 바로가기
Data Analytics with python/[Natural Language]

[정규 표현식] regex 1편

by 보끔밥0130 2023. 1. 28.
728x90

정규 표현식

 

정규 표현식 : 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하는 형식 언어

 

정규표현식은 문자열의 검색과 치환을 위해 지원하고 있습니다.

 

정규 표현식은 메타 문자를 사용하여 특별한 의미를 부여 합니다.

 

메타 문자 : 원래 그 문자가 가진 뜻이 아닌 특별한 용도로 사용하는 문자

. ^ $ * + ? { } [ ] \ | ( )

 

메타 문자 1 : +, * , [ ], {}

특징 : 메타 문자의 매치가 진행될 때 현재 매치되고 있는 문자열의 위치가 변경 됩니다. (문자열을 소비시키는 메타문자)

▶ character class (문자 클래스)

 

기호 : [ ]

 

의미 : 대괄호 사이의 문자들과 매치한다.

 

예시 :

[abc] →  "a, b, c" 중 한 개의 문자와 매치하라는 의미입니다.

 

[a-c] →  a와 c 사이의 범위 들어간 문자와 매치하라는 의미입니다.

 

대표적인 사용 방식으로 "알파벳 모두"를 의미하는 [a-zA-Z] 와 "숫자"를 의미하는 [0-9]가 있습니다.

 

주의해야할 부분은 문자 클래스 내 "^" 기호가 "제외"하라는 의미입니다.

 

가령 [^0-9]는 문자만 매치가 됩니다.

 

♣ 자주 사용하는 정규 표현식 간략화 표기

문자 클래스 의미
\d [0-9]와 동일한 의미, 숫자 매치
\D [^0-9]와 동일한 의미. 숫자 제외한 매치
\s [ \t\n\r\f\v]와 동일한 의미 (맨 앞에 공백(space)가 존재), *whitespace 문자와 매치
\S [^ \t\n\r\f\v]와 동일한 의미, whitespace 문자가 아닌 것과 매치
\w [a-zA-Z0-9_]와 동일한 의미, 문자 + 숫자와 매치
\W [^a-zA-Z0-9_]와 동일한 의미, 문자 + 숫자가 아닌 문자와 매치

* whitespace : 공백형태로 된 문자형태를 의미합니다. (스페이스, 탭, 줄바꿈, 자동줄바꿈 등)

대문자로 사용된 것이 소문자의 반대 의미가 됨을 생각하면 쉽게 생각됩니다.

 

▶ Dot 

● 기호 : " . "

 

 의미 : 한 개의 임의의 문자를 나타냅니다.

줄바꿈(\n)을 제외한 모든 문자와 매치가 됩니다.

단, 만약 줄바꿈도 포함하여 매치하고 싶다면 re.DOTALL이라는 옵션을 사욯하면 됩니다.

import re
p = re.compile('a.b')
m = p.match('a\nb')
print(m)

 

 예시 : a.b → 두 문자 사이에 하나 이상의 어떤 문자가 들어가도 모두 매치됩니다.

 

''acb", "a7b" 는 정규식과 매치가 됩니다. 반면, "abc"는 a와 b 두 문자 사이에 어떤 문자도 없으므로 정규식과 매치가 되지 않습니다.

 

주의사항 : character class 내에 Dot 메타 문자가 사용되는 경우 "모든 문자"라는 의미가 아닌 문자 "." 그대로를 의미합니다.

a[.]b는 "a.b" 문자열만 매치가 됩니다. 

 

▶ 0번 이상 반복

 

 기호 : " * "

 

 의미 : 바로 앞에 있는 한 문자가 반복 횟수 0부터 무한대로 반복될 수 있습니다. (메모리 제한으로 2억 개 제한 됨)

 

 예시 : Do*g 정규식의 경우 "Dg", "Dag", "Daaaaaaag" 등 "a" 가 0번 부터 0번 이상 반복되는 문자열이 모두 매치가 됩니다.

 

 

▶ 1번 이상 반복 

 기호 : " + "

 

 의미 : 바로 앞에 있는 한 문자가 최소 1번 이상 반복될 때 사용합니다.

 

 예시 :  Do+g 정규식의 경우 "Dg"는 매치가 되지 않으며 "Dag", "Daaaaaaag" 등 "a"가 1번 이상 반복되어야 매치가 됩니다.

 

▶ 횟수 고정 반복

 기호 : ① { } ② ?

 의미 : ① {m,n} 정규식 형태로 사용하며 반복 회수를 m부터 n까지 고정할 수 있습니다.

+ → {1,}

* → {0,}

② 앞 문자가 있어도 되고 없어도 매치가 되는 의미, {0,1}과 동일한 의미를 나타냅니다.

 예시 :

{6,} →  반복 횟수 6이상

{,6} → 반복 횟수 6 이하

{6} → 반드시 6번 반복

{2,6} → 2~6회 반복

 

▶ 파이썬 정규 표현식 모듈

re (regular expression) 모듈을 사용합니다.

import re
p = re.compile('ab*')

re.compile이라는 *컴파일 명령어를 사용하여 정규 표현식을 변환해줍니다.

결과를 돌려주는 객체 p(컴파일 된 객체)를 사용하여 그 이후의 작업을 수행 할 수 있습니다.

*컴파일 : 인간이 이해할 수 있는 언어로 작성된 소스 코드 (고수준 언어:  C, python 등)을 CPU가 (컴퓨터) 이해할 수 있는 언어 (저수준 언어: 기계어 0과 1로표시)로 변환하는 작업

 

패턴 : 정규식을 컴파일한 결과물

 

♣ re 모듈을 4가지 메서드를 제공합니다.

ⓛ match() : 문자열의 처음부터 정규식과 매치되는지 조사합니다.

② search() : 문자열 전체를 검색하여 정규식과 매치되는지 조사합니다.

③ findall() : 정규식과 매치되는 모든 문자열을 리스트로 리턴합니다.

④ finditer() : 정규식과 매치되는 모든 문자열을 반복 가능한 객체로 리턴합니다. 

 

♣ match와 search를 수행한 결과로 리턴된 객체와 관련된 명령어

ⓛ group() : 매치된 문자열을 리턴합니다.

② start() : 매치된 문자열의 시작 인덱스를 리턴합니다.

③ end() : 매치된 문자열의 마지막 인덱스를 리턴합니다.

④ span() : 매치된 문자열의 (시작, 끝)의 위치를 튜플로 리턴합니다.

 

메타 문자 2 :  |, ^, $,  ₩A, ₩Z, ₩b

특징 : 메타 문자의 매치가 진행될 때 현재 매치되고 있는 문자열의 위치가 변경 되지 않습니다. (문자열을 소비시키지 않는 메타문자)

▶ |

●기호 : ' | '

 

●의미 : '또는' 둘 중 하나와 매치가 됩니다.

 

●예시: 

import re
p = re.compile('cat|dog')
m = p.search('hotdog')
print(m)

[out] :

<re.Match object; span=(3, 6), match='dog'>

▶ ^

●기호 : " ^ "

 

●의미 : 맨 처음과 일치하는 문자열을 의미합니다.

 

특히, 여러 줄의 문자열일 때 각 줄의 처음과 일치하려면 re.MULTILINE 옵션을 사용하면 됩니다.

 

●예시 : "^re" 정규식은 검색할 문자열이 re로 시작해야 매치가 됩니다.

print(re.search('^re', 're is too complexed'))

[out] :

<re.Match object; span=(0, 2), match='re'>

 

▶ $

●기호 : " $ "

 

●의미 : 맨 끝과 일치하는 문자열을 의미합니다.

 

●예시: "complexed$" 정규식은 검색할 문자열이 complexed로 끝난 경우에 매치가 됩니다.

print(re.search('complexed$', 're is too complexed'))

[out] :

<re.Match object; span=(10, 19), match='complexed'>

 

▶ \A

●의미 : 문자열의 처음과 매치됨을 의미합니다.

 

단, re.MULTILINE 옵션을 사용할 경우 줄과 상관없이 전체 문자열의 처음하고만 매치 됩니다.

▶ \Z

●의미 : 문자열의 끝과 매치됨을 의미합니다.

단,  re.MULTILINE 옵션을 사용할 경우 전체 문자열의 끝과 매치됩니다.

▶ \b

●의미 : 단어를 구분해내는 단어 구분자 입니다. 즉, whitespace로 구분된 단어와 매치가 됩니다.

 

●예시: '\bnormal\b' 정규식은 앞뒤가 공백으로 구분된 normal라는 단어와만 매치됩니다. 

normalization이라는 단어에서의 normal과 매치되지 않습니다.

▶ \B

●의미 : \b 메타 문자와 반대입니다. 즉, whitespace로 구분된 단어가 아닌 경우에만 매치됩니다.

 

●예시 :  '\Bnormal\B'로 위의 경우 normalization의 normal에만 매치가 됩니다. 

 

★ 정규식 쉽게 이해하기

1) 복잡한 정규식

re.VERBOSE 옵션, re.X 옵션

: 복잡한 정규식을 주석 또는 줄 단위로 구분하여 표시하는 방법

charref = re.compile(r"""
^[a-zA-Z0-9+-_.]+     # ID
@[a-zA-Z0-9-]+        # Domain
\.[a-zA-Z0-9-.]+$     # Top-level domain
""", re.VERBOSE)

emails = ['expression@mail.example.com', 'expression+kr@example.com',              # 올바른 형식
          'regular-expression@example.co.kr', 'expression_77@example.info',         # 올바른 형식
          'regular.expression@e-xample.com',                                    # 올바른 형식
          '@example.com', 'python@example', 'python@example-com']          # 잘못된 형식
 
for email in emails:
    print(charref.match(email) != None, end=' ')

 

2) 백슬래시 문제

"\section" 문자열을 찾는 경우 \s문자가 whitespace로 해석되어 매치가 의도와 다르게 이루어지는 경우

p = re.compile('\\section')

백슬러쉬 표현이 계속 반복되는 정규식이라면 위와 같은 방식이 복잡하게 만듭니다.

 

따라서 Raw String 규칙을 활용하여 다음과 같이 표기합니다.

p = re.compile(r'\section')

 

728x90

댓글