[Python] Python re (정규 표현식)

JAsmine_log·2024년 6월 2일
0

Python

Regular expression(정규 표현식)

복잡한 문자열을 처리할 때 사용하는 기법으로, 형식언어(formal lanauage)이다. 파이썬 분만 아니라, 문자열을 처리하기 위한 곳에서는 모두 사용된다고 볼 수 있다. 정규표현식은 정규식이라고도 한다.

필요성

  • 효율성

예제

주민등록 번호를 포함한 보안에 민감한 텍스트 데이터가 있다. 이 때, 주민등록번호를 가명처리 하기 위해서 뒷자리를 모두 * 문자로 변경하고자 한다.

반면, 정규식을 사용하면 다음처럼 훨씬 간편하고 직관적인 코드를 작성할 수 있다. 아직 정규식 사용 방법을 배우지 않았으므로 눈으로만 살펴보자.

일반 코드

정규식을 사용하지 않는 경우에는 아래코드와 같이 문자 라이브러리를 활용해서 문자를 변활한 것이다.

  • 01 전체 텍스트를 .split() 메서드를 사용해 공백으로 분할한다.
  • 02 분할한 단어가 주민등록번호 형식인지 확인한다.
  • 03 주민등록번호 혁식 단어는 뒷자리를 *로 변환한.
  • 04 부할된 단어를 다시 .join()으로 조합한다.
data = """
lee 800905-2049118
hwang 700905-1059119
"""

result = []
for line in data.split("\n"):
    word_result = []
    for word in line.split(" "):
        if len(word) == 14 and word[:6].isdigit() and word[7:].isdigit():
            word = word[:6] + "-" + "*******"
        word_result.append(word)
    result.append(" ".join(word_result))
print("\n".join(result))

>>
lee 800905-*******
hwang  700905-*******

정규표현식

위의 코드에서는 split, join, for loop등 여러 메서드를 사용하여 여러 줄의 코드를 작성하여 문자를 변환하였다. 그러나, 정규표현식을 사용하면 아래와 같이 간단하게 코드를 줄일 수 있다.

import re 

data = """
lee 800905-1049118
hwang  700905-1059119
"""

pat = re.compile("(\d{6})[-]\d{7}")
print(pat.sub("\g<1>-*******", data))

>>
lee 800905-*******
hwnag  700905-*******

메타 문자 (meta character)

원래 문자의 의미가 아닌 특별한 의미를 갖는 문자이다. 아래는 메문자들이다.
. ^ $ * ? { } [ ] \ | ( )

[ ] character class

[, ] 문자 사이에 매치되는 문자를 찾을 수 있다. 이 때, 괄호 안에 포함되는 문자 어떤 것이든 찾아 낸다.
-은 문자사이의 범위를 의미한다.
^은 not을 의미하고, ~을 제외한다는 뜻이다.

  • [abc]

    • 'a' => 'a' 매치
    • 'before' => 'b' 매치
    • 'dude' => 없음
  • [a-c](=[abc])

    • [a-zA-Z]
    • [0-9]
  • [^a-c](=[^abc])

    • [^a-zA-Z] : a-zA-Z 을 제외
    • [^0-9] : 숫자 문자 0-9 제외

문자 클래스 표현

  • \d : 숫자와 매치 - [0-9]
  • \D : 숫자를 제외하고 매치 - [^0-9]
  • \s : 공백(whitespace) 문자 매치 - [ \t\n\r\f\v]
    ( 은 white space)
  • \S : 공백(whitespace) 문자를 제외하고 매치 - [^ \t\n\r\f\v]
  • \w : 문자+숫자(alphanumeric)와 매치 - [a-zA-Z0-9_]
  • \W : 문자+숫자(alphanumeric)를 제외하고 매치 - [^a-zA-Z0-9_]
    ※ 여기서 소문자와 대문자는 서로 반대로 의미함

이스케이프 코드(escape code)
프로그래밍을 위해 미리 정의해둔 문자 조함

  • \n : 문자열 안에서 줄을 바꿀 때 사용
  • \t : 문자열 사이에 탭 간격을 줄 때 사용
  • \r : 캐리지 리턴(줄 바꿈, 커서를 현재 줄의 가장 앞으로 이동)
  • \f : 폼 피드(줄 바꿈, 커서를 다음 줄로 이동)
  • \b : 백 스페이스

.(dot)

\n을 제외한 모든 문자와 매치한다

  • re.DOTALL :., \n도 매치
  • a.b : a + 모든 문자 + b
    • 'aab' : a'a'b는 a가 모든 문자 .에 매치
    • 'a0b' : a'0'b는 0가 모든 문자 .에 매치
    • 'abc' : a'b'c는 b는 모든 문자 .에 매치되지만, c가 일지하지 않음
  • a[.]b : a + . + b
    • [.]와 . 는 다르다.

* 문자

+바로 앞에 있는 문자가 최소 한번 무한대로 반복될 수 있음을 의미한다.

  • ab+c
    • ac : b가 0번 반복되어 매치되지 않음(한 번도 안나올 수 있음)
    • abc : b가 1번 반복되어 매치
    • abbbc : b가 3번(1번이상) 반복되어 매치

+ 문자

+바로 앞에 있는 문자가 무한대로 반복될 수 있음을 의미한다.

  • ab*c
    • ac : b가 0번 반복되어 매치(한 번도 안나올 수 있음)
    • abc : b가 1번 반복되어 매치
    • abbbc : b가 3번 반복되어 매치

{}

반복 회수를 m에서 n번 까지로 제한하기 위해 사용한다.

  • {n} 무조건 n번 반복

  • {m, n}

    • `{m,} : m번 이상
    • `{,n] : 0~n번 이하
    • {1,} == +, {0,} == *
  • ab{2}c

    • abc : b가 1번 반복되어 매치되지 않음
    • abbc : b가 1번 반복되어 매치
  • ab{2,5}c

    • abc : b가 1번 반복되어 매치되지 않음
    • abbc : b가 2번 반복되어 매치
    • abbbbbc : b가 5번 반복되어 매치

?

{0,1} 의미하며, 바로 앞에 문자가 있어도 되고 없어도 된다.

  • ab?c
    • abc : b가 1번 사용되어 매치
    • ac : b가 0번 사용되어 매치

re(regex)

파이썬에서 정규표현식을 지원하는 모듈이다.

re

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

re를 이용한 문자열 검색 메서드

  • match() 문자열이 처음부터 정규식과 매치되는지 조사
  • search() 문자열 전체를 검색하여 정규식과 매치되는지 조사
  • findall() 정규식과 매치되는 모든 하위 문자열(substring)을 리스트로 리턴
  • finditer() 정규식과 매치되는 모든 하위 문자열(substring)을 반복 가능한 객체로 리턴

정규식 메서드를 이용한 검색

정규식은 패턴 검색이라고 볼 수 있다. 다음 패턴을 선언하여 문자열을 검색하여 매치해 보자.

import re
p = re.compile('[a-z]+')

match

  • 첫번째 문자가 소문자 문자열 포함하여 "python"매치
m = p.match("python")
print(m)

>>
<re.Match object; span=(0, 6), match='python'>
  • 문자열의 처음이 숫자 3이라 not 매치
m = p.match("3 python")
print(m)
>> 
None
  • match 함수 사용 예제 : match 여부를 확인하여 활용 가능
p = re.compile(정규표현식)
m = p.match( '조사할 문자열' )
if m:
    print('Match found: ', m.group())
else:
    print('No match')
  • 문자열 전체가 매치
m = p.search("python")
print(m)

>>
<re.Match object; span=(0, 6), match='python'>
  • 첫 번째 문자열은 "3"이지만, "3" 이후의 문자열 전체를 검색하여 "python"이 패턴과 매치
m = p.match("3 python")
print(m)
>> 
<re.Match object; span=(2, 8), match='python'>

findall

아래 문자의 인덱스는

0  1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16
l  i  f  e ` ` i s  ` ` t  o  o  ` `  s   h   o   r   t
result = p.findall("life is too short")
print(result)

>> ['life', 'is', 'too', 'short']

finditer

reuslt = p.finditer("life is too short")
print(result)
>>
<callable_iterator object at 0x01F5E390>
...
<re.Match object; span=(0, 4), match='life'>
<re.Match object; span=(5, 7), match='is'>
<re.Match object; span=(8, 11), match='too'>
<re.Match object; span=(12, 17), match='short'>

match 객체의 메서드

  • group 매치된 문자열 리턴
  • start 매치된 문자열의 시작 위치 리턴
  • end 매치된 문자열의 끝 위치 리턴
  • span 매치된 문자열의 (시작, 끝)에 해당하는 튜플을 리턴
m = p.match("python")
m.group()
>>
'python'
m.start()
>>
0
m.end()
>>
6
m.span()
>>
(0, 6)

컴파일 옵션

  • DOTALL(S) : .는 줄바꿈 문자를 포함해 모든 문자와 매치
  • IGNORECASE(I) : 대소 문자(case)에 관계없이(ignore) 매치
  • MULTILINE(M) : 여러 줄과 매치, ^, $ (메타 문자)와 관계 있음
  • VERBOSE(X) : verbose 모드를 사용, 정규식을 보기 편하게 만들거나, 주석 등을 사용할수 있게 함

역슬래시 문제

r문자를 사용하여 raw string규칙에 의해 역슬래시를 2번쓴 효과를 낸다.

// p1과 p2는 동일한 표현
p1 = re.compile('\\\\section')
p2 = re.compile(r'\\section')

Reference
[1] https://wikidocs.net/1669
[2] https://pypi.org/project/regex/

profile
Everyday Research & Development

0개의 댓글

관련 채용 정보